(转载)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方法中又干了些什么?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152public
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();
12345678910111213protected
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。
12345678protected
ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
//刷新BeanFactory,如果beanFactory为null,则创建
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if
(logger.isDebugEnabled()) {
logger.debug(
"Bean factory for "
+ getDisplayName() +
": "
+ beanFactory);
}
return
beanFactory;
}
refreshBeanFactory()为一抽象方法,真正实现在AbstractRefreshableApplicationContext类中:
12345678910111213141516171819@Override
protected
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。
12345678910111213141516171819protected
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。至此可以来详细分析这三条异常消息的缘由了。
下面是针对上面三条异常消息的三段测试代码,顺序相对应:12345678910111213141516171819201
.
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()方法源码:
1234public
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)这个构造方法最终调用的是:
1234567public
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()方法中:
12345678910@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),例子代码是不会出现异常的。这是因为在refresh方法中的finishRefresh()方法调用了publishEvent方法:
12345678910public
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()方法以获取一个事件广播器,问题就出现在这里:
1234567private
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()方法相关异常的更多相关文章
- 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 ...
随机推荐
- 常见开发需求之前端利器webstorm中的git和快捷键
需求 前端开发中我们最常用的一般是webstorm.hbuilder和sublime,因为以前使用过一段时间eclipse所以我对webstorm的感觉比较良好,再加上以前使用hbuilder维护 ...
- new 等于 malloc加构造函数
1.new 是c++中的操作符,malloc是c 中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员 ...
- table sorting–angularjs
1: <script type="text/javascript" ng:autobind 2: src="http://code.angularjs.org/0. ...
- JSON和JSONP (含jQuery实例)(share)
来源:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 前言: 说到AJAX就会不可避免的面临两个问 ...
- LINUX内核参数网络相关
有助于提高网络性能和吞吐量的参数 net.core.somaxconn = 128 已完成连接队列(completed connection queue) (1)三次握手已经完成,但还未被应用层接收( ...
- CSS中伪类及伪元素用法详解
CSS中伪类及伪元素用法详解 伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的 ...
- --自动创建备份SQL
--自动创建备份SQL DECLARE @dbname VARCHAR(50) ,--要备份的数据库名称 @bakname VARCHAR(50) ,--备份后的bat名称 @sql VARCHAR( ...
- jqgrid cellEdit为true的时候,默认选中单元格值的解决方案
jqgrid cellEdit为true的时候,点击单元格的时候,鼠标在单元格最前面闪. 这时候如果要修改数字内容,非常麻烦.要全选单元格内容,不然不好改. 点击单元格的时候,默认选中单元格值的解决方 ...
- 使用JS实现图片展示瀑布流效果
不知大家有没有发现,一般的图片展示网站都会使用瀑布流效果,所谓的瀑布流 就是网站内的图片不会一下子全缓存出来,而是等你滚动到一定的距离的时候, 下面的图片才会继续缓存,并且图片也是随机出现的,只是宽度 ...
- sql例子
select * from plat_material_resource where stl_url LIKE '/data1/upload%' --截取字符串 UPDATE plat_materia ...