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方法中又干了些什么?

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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();

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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。

 

 

?
1
2
3
4
5
6
7
8
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
     refreshBeanFactory(); //刷新BeanFactory,如果beanFactory为null,则创建
     ConfigurableListableBeanFactory beanFactory = getBeanFactory();
     if (logger.isDebugEnabled()) {
         logger.debug( "Bean factory for " + getDisplayName() + ": " + beanFactory);
     }
     return beanFactory;
}


refreshBeanFactory()为一抽象方法,真正实现在AbstractRefreshableApplicationContext类中:

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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。

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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()方法源码

 

 

?
1
2
3
4
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)这个构造方法最终调用的是:

 

 

?
1
2
3
4
5
6
7
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()方法中:

 

?
1
2
3
4
5
6
7
8
9
10
@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方法:

 

?
1
2
3
4
5
6
7
8
9
10
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()方法以获取一个事件广播器,问题就出现在这里:

 

 

?
1
2
3
4
5
6
7
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()方法,其它情况则会自动调用。

猜你喜欢

转载自jaesonchen.iteye.com/blog/2339714