学习 Spring 源码的建议
- 阅读 Spring 官方文档,了解 Spring 框架的基本概念和使用方法。 
- 下载 Spring 源码,可以从官网或者 GitHub 上获取。 
- 阅读 Spring 源码的入口类,了解 Spring 框架的启动过程和核心组件的加载顺序。 
- 阅读 Spring 源码中的注释和文档,了解每个类和方法的作用和用法。 
- 调试 Spring 源码,可以通过 IDEA 等工具进行调试,了解 Spring 框架的内部实现和运行过程。 
- 参考 Spring 源码的测试用例,了解 Spring 框架的各个组件的使用方法和测试方法。 
- 参考 Spring 源码的设计模式和最佳实践,了解如何设计和实现高质量的 Java 应用程序。 
- 参与 Spring 社区,与其他开发者交流和分享经验,了解 Spring 框架的最新动态和发展趋势。 
学习 Spring 源码的好处
- 更深入地了解 Spring 框架的内部实现和运行机制,可以更好地理解和使用 Spring 框架。 
- 学习 Spring 源码可以提高自己的编程能力和代码质量,了解 Spring 框架的设计模式和最佳实践,可以应用到自己的项目中。 
- 学习 Spring 源码可以帮助开发者解决一些复杂的问题和难点,提高自己的解决问题的能力。 
- 学习 Spring 源码可以帮助开发者更好地理解 Java 语言和面向对象编程的思想,提高自己的编程水平。 
- 学习 Spring 源码可以帮助开发者更好地了解 Java 生态系统和相关技术,如 AOP、IOC、MVC 等。 
- 学习 Spring 源码可以帮助开发者更好地了解开源软件的开发和维护过程,提高自己的开源软件开发能力。 
refresh 方法所出现的问题和异常
最近抽空总结一下之前通用的 Spring 框架所出现的问题和异常情况,当创建属于自己的 ApplicationContext 对象的时候,经常会遇到这么几条异常消息:
- LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: ...... 
LifecycleProcessor 对象没有初始化,在调用 context 的生命周期方法之前必须调用'refresh'方法。
- BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext 
BeanFactory 对象没有初始化或已经关闭了,使用 ApplicationContext 获取 Bean 之前必须调用'refresh'方法。
- ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: ...... 
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
LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context:
 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。
obtainFreshBeanFactory
 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 {  //如果beanFactory已经不为null,则销毁beanFactory中的Bean后自行关闭    if (hasBeanFactory()) {        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。
initApplicationEventMulticaster
 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();}
   复制代码
 
对于第一条异常消息,异常堆栈出错在 applicationContext.start();下面是 start()方法源码:
 public void start() {    getLifecycleProcessor().start();    publishEvent(new ContextStartedEvent(this));}
   复制代码
 
可以看到 start()方法中要先获取 lifecycleProcessor 对象,而默认构造方法中并没用调用 refresh 方法,所以 lifecycleProcessor 为 null,故而在 getLifecycleProcessor()方法中抛出了此异常消息。
异常的测试案例(2)
 public static void main(String[] args) {    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();    applicationContext.setConfigLocation("application-context.xml");    applicationContext.getBean("xtayfjpk");    applicationContext.close();}
   复制代码
 
第二条异常消息,异常堆栈出错在 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,因此抛出异常。
异常的测试案例(3)
 public static void main(String[] args) {    GenericApplicationContext parent = new GenericApplicationContext();    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();    context.setParent(parent);    context.refresh();    context.start();    context.close();}
   复制代码
 
这其中提到了生命周期方法,其实就是定义在 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();    }}
   复制代码
 
第三条异常消息,异常堆栈出错在 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()方法,其它情况则会自动调用。
评论