欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2017年11月16日 14:15:55   作者:xtayfjpk  
這篇文章主要介紹了Spring的refresh()方法相關(guān)異常解析,具有一定參考價(jià)值,需要的朋友可以了解下。

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

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

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

2.BeanFactorynotinitializedoralreadyclosed-call'refresh'beforeaccessingbeansviatheApplicationContext

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

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

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

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

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

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//刷新之前的準(zhǔn)備工作,包括設(shè)置啟動(dòng)時(shí)間,是否激活標(biāo)識(shí)位,初始化屬性源(property source)配置
		prepareRefresh();
		//由子類去刷新BeanFactory(如果還沒創(chuàng)建則創(chuàng)建),并將BeanFactory返回
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		//準(zhǔn)備BeanFactory以供ApplicationContext使用
		prepareBeanFactory(beanFactory);
		try {
			//子類可通過格式此方法來對(duì)BeanFactory進(jìn)行修改
			postProcessBeanFactory(beanFactory);
			//實(shí)例化并調(diào)用所有注冊(cè)的BeanFactoryPostProcessor對(duì)象
			invokeBeanFactoryPostProcessors(beanFactory);
			//實(shí)例化并調(diào)用所有注冊(cè)的BeanPostProcessor對(duì)象
			registerBeanPostProcessors(beanFactory);
			//初始化MessageSource
			initMessageSource();
			//初始化事件廣播器
			initApplicationEventMulticaster();
			//子類覆蓋此方法在刷新過程做額外工作
			onRefresh();
			//注冊(cè)應(yīng)用監(jiān)聽器ApplicationListener
			registerListeners();
			//實(shí)例化所有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;
		}
	}
}

與此三條異常消息相關(guān)的方法分別為:

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

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);
}

如果沒有調(diào)用finishRefresh方法,則lifecycleProcessor成員為null。

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()為一抽象方法,真正實(shí)現(xiàn)在AbstractRefreshableApplicationContext類中:

@Override
protected final void refreshBeanFactory() throws BeansException {
  if (hasBeanFactory()) {//如果beanFactory已經(jīng)不為null,則銷毀beanFactory中的Bean后自行關(guān)閉
    destroyBeans();
    closeBeanFactory();
  }
  try {
    DefaultListableBeanFactory beanFactory = createBeanFactory();//創(chuàng)建beanFactory
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
      this.beanFactory = beanFactory;//對(duì)beanFactory成員進(jìn)行賦值
    }
  }
  catch (IOException ex) {
    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
}

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

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 + "]");
    }
  }
}

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

下面是針對(duì)上面三條異常消息的三段測(cè)試代碼,順序相對(duì)應(yīng):

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();
}

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

public void start() {
  getLifecycleProcessor().start();
  publishEvent(new ContextStartedEvent(this));
}

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

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
  super(parent);
  setConfigLocations(configLocations);
  if (refresh) {//refresh傳遞值為true,這樣就自動(dòng)調(diào)用了refresh方法進(jìn)行了刷新
    refresh();
  }
}

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

@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的默認(rèn)構(gòu)造方法沒有調(diào)用refresh()方法,所以beanFactory為null,因此拋出異常。

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

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,則還需要調(diào)用父容器的pushlishEvent方法,而且在該方法中調(diào)用了getApplicationEventMulticaster()方法以獲取一個(gè)事件廣播器,問題就出現(xiàn)在這里:

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方法在實(shí)例化的,則于父上下文沒有調(diào)用過refresh方法所以父上下文的applicationEventMulticaster成員為null,因此拋出異常。

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

總結(jié)

以上就是本文關(guān)于Spring的refresh()方法相關(guān)異常的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:

Spring集成Redis詳解代碼示例

Spring AOP攔截-三種方式實(shí)現(xiàn)自動(dòng)代理詳解

spring配置掃描多個(gè)包問題解析

如有不足之處,歡迎留言指出。

相關(guān)文章

  • 使用JPA主鍵@Id,@IdClass,@Embeddable,@EmbeddedId問題

    使用JPA主鍵@Id,@IdClass,@Embeddable,@EmbeddedId問題

    這篇文章主要介紹了使用JPA主鍵@Id,@IdClass,@Embeddable,@EmbeddedId問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java阻塞隊(duì)列中的BlockingQueue接口詳解

    Java阻塞隊(duì)列中的BlockingQueue接口詳解

    這篇文章主要介紹了Java阻塞隊(duì)列中的BlockingQueue接口詳解,對(duì)于Queue而言,BlockingQueue是主要的線程安全的版本,具有阻塞功能,可以允許添加、刪除元素被阻塞,直到成功為止,BlockingQueue相對(duì)于Queue而言增加了兩個(gè)方法put、take元素,需要的朋友可以參考下
    2023-09-09
  • 解決SpringCloud Config結(jié)合github無法讀取配置的問題

    解決SpringCloud Config結(jié)合github無法讀取配置的問題

    這篇文章主要介紹了解決SpringCloud Config結(jié)合github無法讀取配置的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java?Spring?Boot請(qǐng)求方式與請(qǐng)求映射過程分析

    Java?Spring?Boot請(qǐng)求方式與請(qǐng)求映射過程分析

    這篇文章主要介紹了Java?Spring?Boot請(qǐng)求方式與請(qǐng)求映射過程分析,Spring?Boot支持Rest風(fēng)格:使用HTTP請(qǐng)求方式的動(dòng)詞來表示對(duì)資源的操作
    2022-06-06
  • java stringbuffer的用法示例

    java stringbuffer的用法示例

    這篇文章主要介紹了java stringbuffer的用法示例,字符串緩沖區(qū),是一個(gè)容器(當(dāng)返回到的是String時(shí)而且長(zhǎng)度不確定,數(shù)據(jù)類型不確定時(shí)就可以用StringBuffer)其實(shí)底層還是數(shù)組,只是被封裝了,對(duì)外提供了方法,初始容量為16個(gè)字符
    2014-01-01
  • Spring中@Value注解的三種使用方式詳解

    Spring中@Value注解的三種使用方式詳解

    這篇文章主要介紹了Spring中@Value注解的三種使用方式詳解,文章通過示例代碼非常詳細(xì)地介紹,對(duì)于每個(gè)人的學(xué)習(xí)或工作都有一定的學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能詳解

    Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能詳解

    這篇文章主要介紹了Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能,較為詳細(xì)的描述了建造者模式的概念、原理并結(jié)合實(shí)例形式分析了Java使用建造者模式實(shí)現(xiàn)的辦理手機(jī)套餐功能具體步驟與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2018-05-05
  • Java中outer標(biāo)簽的用法實(shí)例代碼

    Java中outer標(biāo)簽的用法實(shí)例代碼

    這篇文章主要介紹了Java中outer標(biāo)簽的用法,在這里需要大家注意這里的outer并不是關(guān)鍵字,而僅僅是一個(gè)標(biāo)簽,本文結(jié)合實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下
    2023-01-01
  • Java微服務(wù)分布式調(diào)度Elastic-job環(huán)境搭建及配置

    Java微服務(wù)分布式調(diào)度Elastic-job環(huán)境搭建及配置

    Elastic-Job在配置中提供了JobEventConfiguration,支持?jǐn)?shù)據(jù)庫(kù)方式配置,會(huì)在數(shù)據(jù)庫(kù)中自動(dòng)創(chuàng)建JOB_EXECUTION_LOG和JOB_STATUS_TRACE_LOG兩張表以及若干索引,來記錄作業(yè)的相關(guān)信息
    2023-02-02
  • Java CountDownLatch與CyclicBarrier及Semaphore使用教程

    Java CountDownLatch與CyclicBarrier及Semaphore使用教程

    對(duì)于并發(fā)執(zhí)行,Java中的CountDownLatch是一個(gè)重要的類。為了更好的理解CountDownLatch這個(gè)類,本文將通過例子和源碼帶領(lǐng)大家深入解析CountDownLatch與CyclicBarrier及Semaphore的原理,感興趣的可以學(xué)習(xí)一下
    2023-01-01

最新評(píng)論