Spring的refresh()方法相关异常
来源:互联网 发布:java多级菜单 编辑:程序博客网 时间:2024/06/15 07:23
如果是经常使用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方法中又干了些什么?
与此三条异常消息相关的方法分别为:finishRefresh();obtainFreshBeanFactory();initApplicationEventMulticaster();
如果没有调用finishRefresh方法,则lifecycleProcessor成员为null。
refreshBeanFactory()为一抽象方法,真正实现在AbstractRefreshableApplicationContext类中:
如果没有调用obtainFreshBeanFactory()方法则beanFactory成员为null。
而这三个方法调用都在refresh()方法中,由上面的分析可知,如果没有调用refresh方法,则上下文中的lifecycleProcessor,beanFactory,applicationEventMulticaster成员都会为null。至此可以来详细分析这三条异常消息的缘由了。
下面是针对上面三条异常消息的三段测试代码,顺序相对应:
对于第一条异常消息,异常堆栈出错在applicationContext.start();下面是start()方法源码:
可以看到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)这个构造方法最终调用的是:
由于ClassPathXmlApplicationContext的默认构造方法没有调用refresh()方法,所以beanFactory为null,因此抛出异常。
从上面可以看到:如果父上下文不为null,则还需要调用父容器的pushlishEvent方法,而且在该方法中调用了getApplicationEventMulticaster()方法以获取一个事件广播器,问题就出现在这里:
而applicationEventMulticaster就是在refresh方法中的initApplicationEventMulticaster方法在实例化的,则于父上下文没有调用过refresh方法所以父上下文的applicationEventMulticaster成员为null,因此抛出异常。
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方法中又干了些什么?
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);//初始化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.throw ex;}}}
与此三条异常消息相关的方法分别为:finishRefresh();obtainFreshBeanFactory();initApplicationEventMulticaster();
protected void finishRefresh() {// //初始化LifecycleProcessorinitLifecycleProcessor();// 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();//创建beanFactorybeanFactory.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对象时应该是这样的: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("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()方法,其它情况则会自动调用。
0 0
- Spring的refresh()方法相关异常
- spring 容器的refresh方法
- Spring的refresh()方法调用过程
- Spring 的Refresh()
- spring学习(三)ConfigurableApplicationContext的refresh方法
- Spring源码阅读--AbstractApplicationContext refresh()方法调用
- ConfigurableWebApplicationContext wac的refresh方法
- 浅析Spring IoC源码(三)分析refresh()方法前的准备篇(一)
- spring+hibernate相关异常
- java事务相关异常的排查方法
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析之一
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记1
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记2
- 可以代替窗体Refresh方法的函数
- entityManager 的 merge/refresh/flush 方法
- entityManager 的 merge/refresh/flush 方法
- entityManager 的 merge/refresh/flush 方法
- spring初始化refresh()方法中obtainFreshBeanFactory()源码走读。
- Maximum Gap --LeetCode
- 《Orange's 一个操作系统的实现》学习笔记--特权级代码段之间的转移(四)
- [pyhton]python cookbook学习笔记
- 【Java学习笔记】Comparable接口的实现和使用
- 50个C/C++面试题
- Spring的refresh()方法相关异常
- CocoaPod安装第三方库
- 二路归并排序
- Binary Tree Right Side View
- js中加载并解析xml文件, 动态添加标签,控件
- python strip()函数
- iOS网络编程3—JSON解析
- 转机
- android 集成支付宝(二)