Spring是一個開放源代碼的設計層面框架,他解決的是業務邏輯層和其他各層的松耦合問題,因此它將面向接口的編程思想貫穿整個系統應用。Spring是于2003 年興起的一個輕量級的Java 開發框架,由Rod Johnson創建。簡單來說,Spring是一個分層的JavaSE/EEfull-stack(一站式) 輕量級開源框架。
如果是經常使用Spring,特別有自己新建ApplicationContext對象的經歷的人,肯定見過這么幾條異常消息:
1.LifecycleProcessornotinitialized-call'refresh'beforeinvokinglifecyclemethodsviathecontext:......
2.BeanFactorynotinitializedoralreadyclosed-call'refresh'beforeaccessingbeansviatheApplicationContext
3.ApplicationEventMulticasternotinitialized-call'refresh'beforemulticastingeventsviathecontext:......
第一條消息是說LifecycleProcessor對象沒有初始化,在調用context的生命周期方法之前必須調用'refresh'方法
第二條消息是說BeanFactory對象沒有初始化或已經關閉了,使用ApplicationContext獲取Bean之前必須調用'refresh'方法
第三條消息是說ApplicationEventMulticaster對象沒有初始化,在context廣播事件之前必須調用'refresh'方法
這幾條異常消息都與refresh方法有關,那拋出這些異常的原因到底是什么,為什么在這么多情況下一定要先調用refresh方法(定義在AbstractApplicationContext類中),在此這前我們先看看refresh方法中又干了些什么?
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //刷新之前的準備工作,包括設置啟動時間,是否激活標識位,初始化屬性源(property source)配置 prepareRefresh(); //由子類去刷新BeanFactory(如果還沒創建則創建),并將BeanFactory返回 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //準備BeanFactory以供ApplicationContext使用 prepareBeanFactory(beanFactory); try { //子類可通過格式此方法來對BeanFactory進行修改 postProcessBeanFactory(beanFactory); //實例化并調用所有注冊的BeanFactoryPostProcessor對象 invokeBeanFactoryPostProcessors(beanFactory); //實例化并調用所有注冊的BeanPostProcessor對象 registerBeanPostProcessors(beanFactory); //初始化MessageSource initMessageSource(); //初始化事件廣播器 initApplicationEventMulticaster(); //子類覆蓋此方法在刷新過程做額外工作 onRefresh(); //注冊應用監聽器ApplicationListener registerListeners(); //實例化所有non-lazy-init bean finishBeanFactoryInitialization(beanFactory); //刷新完成工作,包括初始化LifecycleProcessor,發布刷新完成事件等 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();
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。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory();//刷新BeanFactory,如果beanFactory為null,則創建 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory;}
refreshBeanFactory()為一抽象方法,真正實現在AbstractRefreshableApplicationContext類中:
@Overrideprotected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) {//如果beanFactory已經不為null,則銷毀beanFactory中的Bean后自行關閉 destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory();//創建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。
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. 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()方法源碼:
public void start() { getLifecycleProcessor().start(); publishEvent(new ContextStartedEvent(this));}
可以看到start()方法中要先獲取lifecycleProcessor對象,而默認構造方法中并沒用調用refresh方法,所以lifecycleProcessor為null,故而在getLifecycleProcessor()方法中拋出了此異常消息。這其中提到了生命周期方法,其實就是定義在org.springframework.context.Lifecycle接口中的start(),stop(),isRunning()三個方法,如果是剛開始學習Spring的話,創建ClassPathXmlApplicationContext對象時應該是這樣的:ClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("application-context.xml");這樣直接調用start()方法卻又不會出現異常,這是為什么呢?這是因為ClassPathXmlApplicationContext(StringconfigLocation)這個構造方法最終調用的是:
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()方法實現的,獲取BeanFactory對象的代碼在其基類ConfigurableListableBeanFactory中的getBeanFactory()方法中:
@Overridepublic 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),例子代碼是不會出現異常的。這是因為在refresh方法中的finishRefresh()方法調用了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,則還需要調用父容器的pushlishEvent方法,而且在該方法中調用了getApplicationEventMulticaster()方法以獲取一個事件廣播器,問題就出現在這里:
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,因此拋出異常。
綜上所述,其實這三條異常消息的根本原因只有一個,就是當一個上下文對象創建后沒有調用refresh()方法。在Spring中ApplicationContext實現類有很多,有些實現類在創建的過程中自動調用了refresh()方法,而有些又沒有,如果沒有則需要自己手動調用refresh()方法。一般說來實現WebApplicationContext接口的實現類以及使用默認構造方法創建上下文對象時不會自動refresh()方法,其它情況則會自動調用。
總結
以上就是本文關于Spring的refresh()方法相關異常的全部內容,希望對大家有所幫助。
新聞熱點
疑難解答
圖片精選