一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring的refresh()方法相關異常解析

Spring的refresh()方法相關異常解析

2021-02-06 11:42xtayfjpk Java教程

這篇文章主要介紹了Spring的refresh()方法相關異常解析,具有一定參考價值,需要的朋友可以了解下。

Spring是一個開放源代碼的設計層面框架,他解決的是業(yè)務邏輯層和其他各層的松耦合問題,因此它將面向接口的編程思想貫穿整個系統(tǒng)應用。Spring是于2003 年興起的一個輕量級的Java 開發(fā)框架,由Rod Johnson創(chuàng)建。簡單來說,Spring是一個分層的JavaSE/EEfull-stack(一站式) 輕量級開源框架。

如果是經(jīng)常使用Spring,特別有自己新建ApplicationContext對象的經(jīng)歷的人,肯定見過這么幾條異常消息:

1.LifecycleProcessornotinitialized-call'refresh'beforeinvokinglifecyclemethodsviathecontext:......

2.BeanFactorynotinitializedoralreadyclosed-call'refresh'beforeaccessingbeansviatheApplicationContext

3.ApplicationEventMulticasternotinitialized-call'refresh'beforemulticastingeventsviathecontext:......

第一條消息是說LifecycleProcessor對象沒有初始化,在調用context的生命周期方法之前必須調用'refresh'方法

第二條消息是說BeanFactory對象沒有初始化或已經(jīng)關閉了,使用ApplicationContext獲取Bean之前必須調用'refresh'方法

第三條消息是說ApplicationEventMulticaster對象沒有初始化,在context廣播事件之前必須調用'refresh'方法

這幾條異常消息都與refresh方法有關,那拋出這些異常的原因到底是什么,為什么在這么多情況下一定要先調用refresh方法(定義在AbstractApplicationContext類中),在此這前我們先看看refresh方法中又干了些什么?

java" id="highlighter_928635">
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //刷新之前的準備工作,包括設置啟動時間,是否激活標識位,初始化屬性源(property source)配置
        prepareRefresh();
        //由子類去刷新BeanFactory(如果還沒創(chuàng)建則創(chuàng)建),并將BeanFactory返回
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //準備BeanFactory以供ApplicationContext使用
        prepareBeanFactory(beanFactory);
        try {
            //子類可通過格式此方法來對BeanFactory進行修改
            postProcessBeanFactory(beanFactory);
            //實例化并調用所有注冊的BeanFactoryPostProcessor對象
            invokeBeanFactoryPostProcessors(beanFactory);
            //實例化并調用所有注冊的BeanPostProcessor對象
            registerBeanPostProcessors(beanFactory);
            //初始化MessageSource
            initMessageSource();
            //初始化事件廣播器
            initApplicationEventMulticaster();
            //子類覆蓋此方法在刷新過程做額外工作
            onRefresh();
            //注冊應用監(jiān)聽器ApplicationListener
            registerListeners();
            //實例化所有non-lazy-init bean
            finishBeanFactoryInitialization(beanFactory);
            //刷新完成工作,包括初始化LifecycleProcessor,發(fā)布刷新完成事件等
            finishRefresh();
        }
        catch (BeansException ex) {
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
    }
}

與此三條異常消息相關的方法分別為:

finishRefresh();obtainFreshBeanFactory();initApplicationEventMulticaster();

?
1
2
3
4
5
6
7
8
9
10
protected void finishRefresh() {
    // //初始化LifecycleProcessor
    initLifecycleProcessor();
    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();
    // Publish the final event.
    publishEvent(new ContextRefreshedEvent(this));
    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

如果沒有調用finishRefresh方法,則lifecycleProcessor成員為null。

?
1
2
3
4
5
6
7
8
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  refreshBeanFactory();//刷新BeanFactory,如果beanFactory為null,則創(chuàng)建
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  }
  return beanFactory;
}

refreshBeanFactory()為一抽象方法,真正實現(xiàn)在AbstractRefreshableApplicationContext類中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected final void refreshBeanFactory() throws BeansException {
  if (hasBeanFactory()) {//如果beanFactory已經(jīng)不為null,則銷毀beanFactory中的Bean后自行關閉
    destroyBeans();
    closeBeanFactory();
  }
  try {
    DefaultListableBeanFactory beanFactory = createBeanFactory();//創(chuàng)建beanFactory
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
      this.beanFactory = beanFactory;//對beanFactory成員進行賦值
    }
  }
  catch (IOException ex) {
    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
}

如果沒有調用obtainFreshBeanFactory()方法則beanFactory成員為null。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void initApplicationEventMulticaster() {
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    this.applicationEventMulticaster =
        beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    if (logger.isDebugEnabled()) {
      logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    }
  }
  else {
    this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    if (logger.isDebugEnabled()) {
      logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
          APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
          "': using default [" + this.applicationEventMulticaster + "]");
    }
  }
}

而這三個方法調用都在refresh()方法中,由上面的分析可知,如果沒有調用refresh方法,則上下文中的lifecycleProcessor,beanFactory,applicationEventMulticaster成員都會為null。至此可以來詳細分析這三條異常消息的緣由了。

下面是針對上面三條異常消息的三段測試代碼,順序相對應:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. public static void main(String[] args) {
  ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
  applicationContext.setConfigLocation("application-context.xml");
  applicationContext.start();
  applicationContext.close();
}
2. public static void main(String[] args) {
  ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
  applicationContext.setConfigLocation("application-context.xml");
  applicationContext.getBean("xtayfjpk");
  applicationContext.close();
}
3. public static void main(String[] args) {
  GenericApplicationContext parent = new GenericApplicationContext();
  AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
  context.setParent(parent);
  context.refresh();
  context.start();
  context.close();
}

對于第一條異常消息,異常堆棧出錯在applicationContext.start();下面是start()方法源碼:

?
1
2
3
4
public void start() {
  getLifecycleProcessor().start();
  publishEvent(new ContextStartedEvent(this));
}

可以看到start()方法中要先獲取lifecycleProcessor對象,而默認構造方法中并沒用調用refresh方法,所以lifecycleProcessor為null,故而在getLifecycleProcessor()方法中拋出了此異常消息。這其中提到了生命周期方法,其實就是定義在org.springframework.context.Lifecycle接口中的start(),stop(),isRunning()三個方法,如果是剛開始學習Spring的話,創(chuàng)建ClassPathXmlApplicationContext對象時應該是這樣的:ClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("application-context.xml");這樣直接調用start()方法卻又不會出現(xiàn)異常,這是為什么呢?這是因為ClassPathXmlApplicationContext(StringconfigLocation)這個構造方法最終調用的是:

?
1
2
3
4
5
6
7
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
  super(parent);
  setConfigLocations(configLocations);
  if (refresh) {//refresh傳遞值為true,這樣就自動調用了refresh方法進行了刷新
    refresh();
  }
}

第二條異常消息,異常堆棧出錯在applicationContext.getBean("xtayfjpk"),applicationContext.getBean()方法調用的是上下文中beanFactory的getBean()方法實現(xiàn)的,獲取BeanFactory對象的代碼在其基類ConfigurableListableBeanFactory中的getBeanFactory()方法中:

?
1
2
3
4
5
6
7
8
9
10
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
  synchronized (this.beanFactoryMonitor) {
    if (this.beanFactory == null) {
      throw new IllegalStateException("BeanFactory not initialized or already closed - " +
          "call 'refresh' before accessing beans via the ApplicationContext");
    }
    return this.beanFactory;
  }
}

由于ClassPathXmlApplicationContext的默認構造方法沒有調用refresh()方法,所以beanFactory為null,因此拋出異常。

第三條異常消息,異常堆棧出錯在context.refresh(),但是如果沒有設置父上下文的話context.setParent(parent),例子代碼是不會出現(xiàn)異常的。這是因為在refresh方法中的finishRefresh()方法調用了publishEvent方法:

?
1
2
3
4
5
6
7
8
9
10
public void publishEvent(ApplicationEvent event) {
  Assert.notNull(event, "Event must not be null");
  if (logger.isTraceEnabled()) {
    logger.trace("Publishing event in " + getDisplayName() + ": " + event);
  }
  getApplicationEventMulticaster().multicastEvent(event);
  if (this.parent != null) {
    this.parent.publishEvent(event);
  }
}

從上面可以看到:如果父上下文不為null,則還需要調用父容器的pushlishEvent方法,而且在該方法中調用了getApplicationEventMulticaster()方法以獲取一個事件廣播器,問題就出現(xiàn)在這里:

?
1
2
3
4
5
6
7
private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
  if (this.applicationEventMulticaster == null) {//如果為null則拋異常
    throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
        "call 'refresh' before multicasting events via the context: " + this);
  }
  return this.applicationEventMulticaster;
}

而applicationEventMulticaster就是在refresh方法中的initApplicationEventMulticaster方法在實例化的,則于父上下文沒有調用過refresh方法所以父上下文的applicationEventMulticaster成員為null,因此拋出異常。

綜上所述,其實這三條異常消息的根本原因只有一個,就是當一個上下文對象創(chuàng)建后沒有調用refresh()方法。在Spring中ApplicationContext實現(xiàn)類有很多,有些實現(xiàn)類在創(chuàng)建的過程中自動調用了refresh()方法,而有些又沒有,如果沒有則需要自己手動調用refresh()方法。一般說來實現(xiàn)WebApplicationContext接口的實現(xiàn)類以及使用默認構造方法創(chuàng)建上下文對象時不會自動refresh()方法,其它情況則會自動調用。

總結

以上就是本文關于Spring的refresh()方法相關異常的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。

原文鏈接:https://www.2cto.com/kf/201504/389182.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲 另类 欧美 变态屎尿 | 亚洲国产成人精品激情 | 国内自拍2020 | 日产乱码2021永久手机版 | 天天干夜夜拍 | 奇米影视中文字幕 | 国产传媒天美果冻 | 四虎永久免费地址ww417 | 99在线免费视频 | 亚洲高清免费在线观看 | 高清国产激情视频在线观看 | 胸大的姑娘中文字幕视频 | 日韩免费一区 | 阿 好深 快点 老师受不了 | 天码毛片一区二区三区入口 | 亚洲成人伦理 | 成人午夜视频一区二区国语 | 亚洲图片综合区 | 亚洲性网 | 日韩二三区 | 91久久精品青青草原伊人 | 欧美一区二区三区精品 | 女明星放荡高h日常生活 | 亚洲444777KKK在线观看 | 欧美日韩精品一区二区三区高清视频 | 国产精品久久久精品视频 | 精品在线免费观看 | 污到你怀疑人生 | 香蕉久久网 | 国产精品青青青高清在线观看 | 欧美侏儒xxx | 美女扒开腿让男生捅 | 亚洲午夜精品久久久久 | 婷婷影院在线观看 | 精新精新国产自在现 | evelynlin亚裔播放| 手机免费在线视频 | 91动漫在线观看 | 夫妻性生活在线 | 色天使亚洲综合在线观看 | 色综色|