[深入浅出Spring原理及实战]「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常

科技资讯 投稿 7000 0 评论

[深入浅出Spring原理及实战]「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常

学习Spring源码的建议

  1. 下载Spring源码,可以从官网或者GitHub上获取。

  2. 阅读Spring源码中的注释和文档,了解每个类和方法的作用和用法。

  3. 参考Spring源码的测试用例,了解Spring框架的各个组件的使用方法和测试方法。

  4. 参与Spring社区,与其他开发者交流和分享经验,了解Spring框架的最新动态和发展趋势。


学习Spring源码的好处

  1. 学习Spring源码可以提高自己的编程能力和代码质量,了解Spring框架的设计模式和最佳实践,可以应用到自己的项目中。

  2. 学习Spring源码可以帮助开发者更好地理解Java语言和面向对象编程的思想,提高自己的编程水平。

  3. 学习Spring源码可以帮助开发者更好地了解开源软件的开发和维护过程,提高自己的开源软件开发能力。

refresh方法所出现的问题和异常

    LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: ......

LifecycleProcessor对象没有初始化,在调用context的生命周期方法之前必须调用'refresh'方法。

  1. BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext

  1. ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: ......

ApplicationEventMulticaster对象没有初始化,在context广播事件之前必须调用'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

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类中:

@Override
protected 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(方法中:

@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,因此抛出异常。

异常的测试案例(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"。

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(方法,其它情况则会自动调用。

编程笔记 » [深入浅出Spring原理及实战]「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常

赞同 (33) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽