Spring的refresh()方法相关异常
如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息:
LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: ......
BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: ......
第一条消息是说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
。至此可以来详细分析这三条异常消息的缘由了。
下面是针对上面三条异常消息的三段测试代码,顺序相对应:
public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();applicationContext.setConfigLocation("application-context.xml");applicationContext.start();applicationContext.close();}
public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();applicationContext.setConfigLocation("application-context.xml"); // 由《Java精讲》公众号原创applicationContext.getBean("javaessence");applicationContext.close();}
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
对象时应该是这样的:ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
这样直接调用start()
方法却又不会出现异常,这是为什么呢?这是因为ClassPathXmlApplicationContext(String configLocation)
这个构造方法最终调用的是:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) {//refresh传递值为true,这样就自动调用了refresh方法进行了刷新 refresh(); }}
第二条异常消息,异常堆栈出错在applicationContext.getBean("javaessence")
,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()
方法,其它情况则会自动调用。
-------------------------------- END -------------------------------
及时获取更多精彩文章,请关注公众号《Java精讲》。
©著作权归作者所有:来自51CTO博客作者Java精讲的原创作品,如需转载,请注明出处,否则将追究法律责任好知识,才能预见未来
赞赏
0人进行了赞赏支持
更多相关文章
- 2021年面试:整理出一份高级iOS面试题!
- metilene:从BS-seq数据快速敏感地调用差异甲基化区域
- Java反射说得透彻一些
- MySQL Load data多种使用方法
- 中介效应最新进展: 中介效应中的工具变量法使用方法及其代码!
- AER强调计量方法的重要性, 经济学因果分析中的p值操纵和发表偏倚
- serialVersionUID作用是什么以及如何生成的?
- uni-app页面生命与vue生命周期
- 面试题:预训练方法 BERT和OpenAI GPT有什么区别?