(转载)Spring的refresh()方法相关异常
- 如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息:
1.LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: ......
2.BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
3.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方法中又干了些什么?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152publicvoidrefresh()throwsBeansException, 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);//初始化MessageSourceinitMessageSource();//初始化事件广播器initApplicationEventMulticaster();//子类覆盖此方法在刷新过程做额外工作onRefresh();//注册应用监听器ApplicationListenerregisterListeners();//实例化所有non-lazy-init beanfinishBeanFactoryInitialization(beanFactory);//刷新完成工作,包括初始化LifecycleProcessor,发布刷新完成事件等finishRefresh();}catch(BeansException ex) {// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throwex;}}}与此三条异常消息相关的方法分别为:finishRefresh();obtainFreshBeanFactory();initApplicationEventMulticaster();
12345678910111213protectedvoidfinishRefresh() {// //初始化LifecycleProcessorinitLifecycleProcessor();// Propagate refresh to lifecycle processor first.getLifecycleProcessor().onRefresh();// Publish the final event.publishEvent(newContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);}如果没有调用finishRefresh方法,则lifecycleProcessor成员为null。
12345678protectedConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();//刷新BeanFactory,如果beanFactory为null,则创建ConfigurableListableBeanFactory beanFactory = getBeanFactory();if(logger.isDebugEnabled()) {logger.debug("Bean factory for "+ getDisplayName() +": "+ beanFactory);}returnbeanFactory;}refreshBeanFactory()为一抽象方法,真正实现在AbstractRefreshableApplicationContext类中:
12345678910111213141516171819@OverrideprotectedfinalvoidrefreshBeanFactory()throwsBeansException {if(hasBeanFactory()) {//如果beanFactory已经不为null,则销毁beanFactory中的Bean后自行关闭destroyBeans();closeBeanFactory();}try{DefaultListableBeanFactory beanFactory = createBeanFactory();//创建beanFactorybeanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);synchronized(this.beanFactoryMonitor) {this.beanFactory = beanFactory;//对beanFactory成员进行赋值}}catch(IOException ex) {thrownewApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex);}}如果没有调用obtainFreshBeanFactory()方法则beanFactory成员为null。
12345678910111213141516171819protectedvoidinitApplicationEventMulticaster() {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 =newSimpleApplicationEventMulticaster(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。至此可以来详细分析这三条异常消息的缘由了。
下面是针对上面三条异常消息的三段测试代码,顺序相对应:12345678910111213141516171819201.publicstaticvoidmain(String[] args) {ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext();applicationContext.setConfigLocation("application-context.xml");applicationContext.start();applicationContext.close();}2.publicstaticvoidmain(String[] args) {ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext();applicationContext.setConfigLocation("application-context.xml");applicationContext.getBean("xtayfjpk");applicationContext.close();}3.publicstaticvoidmain(String[] args) {GenericApplicationContext parent =newGenericApplicationContext();AnnotationConfigWebApplicationContext context =newAnnotationConfigWebApplicationContext();context.setParent(parent);context.refresh();context.start();context.close();}对于第一条异常消息,异常堆栈出错在applicationContext.start();下面是start()方法源码:
1234publicvoidstart() {getLifecycleProcessor().start();publishEvent(newContextStartedEvent(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)这个构造方法最终调用的是:
1234567publicClassPathXmlApplicationContext(String[] configLocations,booleanrefresh, ApplicationContext parent)throwsBeansException {super(parent);setConfigLocations(configLocations);if(refresh) {//refresh传递值为true,这样就自动调用了refresh方法进行了刷新refresh();}}第二条异常消息,异常堆栈出错在applicationContext.getBean("xtayfjpk"),applicationContext.getBean()方法调用的是上下文中beanFactory的getBean()方法实现的,获取BeanFactory对象的代码在其基类ConfigurableListableBeanFactory中的getBeanFactory()方法中:
12345678910@OverridepublicfinalConfigurableListableBeanFactory getBeanFactory() {synchronized(this.beanFactoryMonitor) {if(this.beanFactory ==null) {thrownewIllegalStateException("BeanFactory not initialized or already closed - "+"call 'refresh' before accessing beans via the ApplicationContext");}returnthis.beanFactory;}}由于ClassPathXmlApplicationContext的默认构造方法没有调用refresh()方法,所以beanFactory为null,因此抛出异常。
第三条异常消息,异常堆栈出错在context.refresh(),但是如果没有设置父上下文的话context.setParent(parent),例子代码是不会出现异常的。这是因为在refresh方法中的finishRefresh()方法调用了publishEvent方法:
12345678910publicvoidpublishEvent(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()方法以获取一个事件广播器,问题就出现在这里:
1234567privateApplicationEventMulticaster getApplicationEventMulticaster()throwsIllegalStateException {if(this.applicationEventMulticaster ==null) {//如果为null则抛异常thrownewIllegalStateException("ApplicationEventMulticaster not initialized - "+"call 'refresh' before multicasting events via the context: "+this);}returnthis.applicationEventMulticaster;}而applicationEventMulticaster就是在refresh方法中的initApplicationEventMulticaster方法在实例化的,则于父上下文没有调用过refresh方法所以父上下文的applicationEventMulticaster成员为null,因此抛出异常。
综上所述,其实这三条异常消息的根本原因只有一个,就是当一个上下文对象创建后没有调用refresh()方法。在Spring中ApplicationContext实现类有很多,有些实现类在创建的过程中自动调用了refresh()方法,而有些又没有,如果没有则需要自己手动调用refresh()方法。一般说来实现WebApplicationContext接口的实现类以及使用默认构造方法创建上下文对象时不会自动refresh()方法,其它情况则会自动调用。
(转载)Spring的refresh()方法相关异常的更多相关文章
- Spring的refresh()方法相关异常
如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息:1.LifecycleProcessor not initialized - c ...
- Spring源码 15 IOC refresh方法10
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 08 IOC refresh方法3
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 07 IOC refresh方法2
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 06 IOC refresh方法1
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获
spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获 当你的某个控制器内的某个方法报错,基本上回显示出java错误代码,非常不友好,这 ...
- Spring AbstractApplicationContext抽象类的refresh()方法--笔记
Spring中AbstractApplicationContext抽象类的refresh()方法是用来刷新Spring的应用上下文的.下面Spring的应用上下文我都叫作context @Overri ...
- spring容器的refresh方法分析
spring源码版本5.0.5 Spring容器创建之后,会调用它的refresh方法刷新Spring应用的上下文. 首先整体查看AbstractApplicationContext#refresh源 ...
- Spring源码 18 IOC refresh方法13
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
随机推荐
- Ajax请求安全性讨论
今天我们来讨论一下ajax请求的安全性,我相信各位在系统开发过程中肯定会绞尽脑汁的想怎样可以尽量少的防止伪造ajax请求进行攻击,尤其是开发跟用户交互比较多的互联网系统.那么就请大家来分享讨论一下你在 ...
- [C++11][算法][穷举]输出背包问题的所有可满足解
关于背包问题的题目,前人之述备矣,这里只讨论实现 输入: n ca w_1 v_1 w_2 v_2 ... w_n v_n 其中,n是物品总数,ca是背包大小,w_n是第n个物品的重量,v_n是第n个 ...
- freemarker内置函数和用法
原文链接:http://www.iteye.com/topic/908500 在我们应用Freemarker 过程中,经常会操作例如字符串,数字,集合等,却不清楚Freemrker 有没有类似于Jav ...
- QA is more than Testing
前话:在测试这个行业做了挺多年了,都快忘记自己大学的专业是国际经济与贸易,一个选择可能就决定了一生的方向. 但既然做了选择,就走下去. ----------------- 在这么多年的工作中,测试始终 ...
- [leetcode] 13. Roman to Integer
如果某一个字母代表的数字大于上一个字母代表的数字小,那么加上这个数字,否则,减去两倍的前一个数字,然后加上这一位数字. public class Solution { private static c ...
- [leetcode] 题型整理之动态规划
动态规划属于技巧性比较强的题目,如果看到过原题的话,对解题很有帮助 55. Jump Game Given an array of non-negative integers, you are ini ...
- hihoCoder1388 Periodic Signal(2016北京网赛F:NTT)
题目 Source http://hihocoder.com/problemset/problem/1388 Description Profess X is an expert in signal ...
- Linux UBI子系统设计初探
问题领域 flash存储设备存在如下特点: 存在坏块 使用寿命较短 存储介质不稳定 读写速度慢 不支持随机访问(nand) 只能通过擦除将0改成1 最小读写单位为page or sub-page 便宜 ...
- 摘要: Linux下which、whereis、locate、find命令的区别
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.这些是从网上找到的资料,因为有时很长时间不会用到,当要用的时候经常弄混了,所以放到这里方便使用. which ...
- 序列流 SequenceInputStream
SequenceInputStream:序列流,对多个流进行合并. SequenceInputStream 表示其他输入流的逻辑串联.它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末 ...