如果是经常使用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方法中又干了些什么?

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。至此可以来详细分析这三条异常消息的缘由了。

下面是针对上面三条异常消息的三段测试代码,顺序相对应:

  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");   // 由《Java精讲》公众号原创applicationContext.getBean("javaessence");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方法,所以lifecycleProcessornull,故而在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()方法调用的是上下文中beanFactorygetBean()方法实现的,获取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()方法,所以beanFactorynull,因此抛出异常。

第三条异常消息,异常堆栈出错在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人进行了赞赏支持

更多相关文章

  1. 2021年面试:整理出一份高级iOS面试题!
  2. metilene:从BS-seq数据快速敏感地调用差异甲基化区域
  3. Java反射说得透彻一些
  4. MySQL Load data多种使用方法
  5. 中介效应最新进展: 中介效应中的工具变量法使用方法及其代码!
  6. AER强调计量方法的重要性, 经济学因果分析中的p值操纵和发表偏倚
  7. serialVersionUID作用是什么以及如何生成的?
  8. uni-app页面生命与vue生命周期
  9. 面试题:预训练方法 BERT和OpenAI GPT有什么区别?

随机推荐

  1. Android:什么情况?
  2. Android开发集锦之二:android中的数据库操
  3. Android布局优化(四)X2C — 提升布局加载速
  4. Android开发中Virtual Device仿真界面对
  5. Android(安卓)Api 常用类库包介绍
  6. 如何在Android中启动JAVA程序
  7. Android模拟器无法上网的解决方法
  8. 获取 + 查看 Android 源码的 方法
  9. android矢量图vector的简单介绍
  10. Android实现动态改变屏幕方向(Landscape &