Spring context的refresh函数执行过程分析

Posted nullifier

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring context的refresh函数执行过程分析相关的知识,希望对你有一定的参考价值。

今天看了一下Spring Boot的run函数运行过程,发现它调用了Context中的refresh函数。所以先分析一下Spring context的refresh过程,然后再分析Spring boot中run的流程。

首先我们找到spring-context组件的AbstractApplicationContext类下的refresh函数:

    @Override
    public void refresh() throws BeansException, IllegalStateException 
        synchronized (this.startupShutdownMonitor) 
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try 
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            

            catch (BeansException ex) 
                if (logger.isWarnEnabled()) 
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset ‘active‘ flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            

            finally 
                // Reset common introspection caches in Spring‘s core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            
        
    

prepareRefresh()

 

    protected void prepareRefresh() 
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

......

        // Initialize any placeholder property sources in the context environment.
        initPropertySources();

        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) 
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        
        else 
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    

可以看到,这个函数做了一些准备工作,记录了refresh的开始时间,调用了留给子类重写的initPropertySources()函数。

验证了环境中必要的参数,并且将earlyListeners加入到应用程序的监听器列表中。

 

obtainFreshBeanFactory() 

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() 
        refreshBeanFactory();
        return getBeanFactory();
    

可以看见,refreshBeanFactory()和getBeanFactory()都是abstract函数,这两个函数设计出来就是为了让子类重写,根据子类实现具体功能,从函数名可以推断出这两个函数一个是用来初始化beanFactory,另外一个则是拿到beanFactory的实例,我们以AbstractRefreshableApplicationContext类的代码为例:

refreshBeanFactory:

    @Override
    protected final void refreshBeanFactory() throws BeansException 
        if (hasBeanFactory()) //如果beanFactory已经被初始化过,则在此销毁
            destroyBeans();
            closeBeanFactory();
        
        try //这里其实就是new了一个DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            //客制化beanFactory,例如设置能否循环引用,能否重写bean等
            customizeBeanFactory(beanFactory);
            //将xml中的bean定义加载到spring-core的注册中心中
            loadBeanDefinitions(beanFactory);
            //设置beanFactory,供getBeanFactory取得
            synchronized (this.beanFactoryMonitor) 
                this.beanFactory = beanFactory;
            
        
        catch (IOException ex) 
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        
    

getBeanFactory:不难想象,这个函数从this类中拿到beanFactory实例并返回。

 

prepareBeanFactory(beanFactory)

 篇幅原因就不贴这部分代码,实在太长,这个函数主要做了如下几件事:

1. 设置了beanFactory的classloader

2. 设置了SpEL的解析器

3. 设置了PropertyEditor,这个是用来将xml里面的占位符解析成具体值的,例如xml里面写<... value="$predefined-var"/>,在PropertyEditor可以将$predefined-var解析为某个具体值,并且到时候生成的beanDefinition对应的field就是这个具体的值。这一步会发生在xml被转换为beanDefinition之前

4. 增加ApplicationContextAwareProcessor的BeanPostProcessor,这个是为了让实现了ApplicationContextAware接口的bean在初始化后自身被注入当前的ApplicationContext,实现对自己所在的Context的感知

5. 忽略下述接口的依赖注入:

EnvironmentAware.class
EmbeddedValueResolverAware.class
ResourceLoaderAware.class
ApplicationEventPublisherAware.class
MessageSourceAware.class
ApplicationContextAware.class

观察上述接口的特征,发现这些都是Aware系列接口,用于使Bean感知环境中的参数(例如当前Context)。自动装配不会对这些接口进行处理,实际上实现了这些接口的类会在Spring中有专门的函数进行处理。

6. 对于一些特定的接口实现,定义默认的注入值:

BeanFactory.class
ResourceLoader.class
ApplicationEventPublisher.class
ApplicationContext.class

这些接口是用来获取关于Spring本身相关的信息的,例如Spring本身的BeanFactory等。

7. 注册一些环境相关的bean,例如systemProperties、systemEnvironment和environment

postProcessBeanFactory(beanFactory)

这个函数实际上是空的:

    /**
     * Modify the application context‘s internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for registering special
     * BeanPostProcessors etc in certain ApplicationContext implementations.
     * @param beanFactory the bean factory used by the application context
     */
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
    

通过上面的注释,我们可以知道,当所有的xml已经被载入并且产生了对应的beanDefinition时,这个函数将会被调用,此时bean的实例都没有产生,在此处可以对beanDefinition的属性进行修改、抑或是注册特别的beanPostProcessor用于对实例化的bean做最终处理。

这里函数留空是为了让用户能够子类化,然后在里面写入自己需要的修改,典型的模板设计模式

 

invokeBeanFactoryPostProcessors(beanFactory)

 调用所有在容器中注册的BeanFactoryPostProcessor

 

registerBeanPostProcessors(beanFactory)

 注册BeanPostProcessors,将所有在xml中定义的beanPostProcessors加入到当前BeanFactory的列表,以便在getBean的时候调用。

 

initMessageSource()

 初始化消息源

 

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.isTraceEnabled()) 
                logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            
        
        else 
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isTraceEnabled()) 
                logger.trace("No ‘" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "‘ bean, using " +
                        "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            
        
    

通过Spring容器得到一个applicationEventMulticaster,如果Spring容器没有定义,则创建SimpleApplicationEventMulticaster作为applicationEventMulticaster。

通过SimpleApplicationEventMulticaster的代码我们也能推断出这个类的作用,就是向Context里面的EventListener发布消息:

    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) 
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        //将当前的事件event发送给当前Context的每一个Listener
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) 
            //如果有executor则使用executor执行
            if (executor != null) 
                executor.execute(() -> invokeListener(listener, event));
            
            else 
                //否则直接在当前线程执行
                invokeListener(listener, event);
            
        
    

 

onRefresh()

这是模板方法,留给子类实现并执行想要的操作

 

registerListeners()

这一步将注册Listener,供前面initApplicationEventMulticaster注册的EventMulticaster进行广播,代码如下:

    protected void registerListeners() 
        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) 
            getApplicationEventMulticaster().addApplicationListener(listener);
        

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) 
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) 
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) 
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            
        
    

这段代码将静态注册的Listener和Spring中注册的Listener bean都添加到EventMulticaster中,这样从EventMulticaster中发布的消息,每个Listener都能监听到,典型的观察者模式。

值得注意的是,Context中包含earlyApplicationEvents,所有的Listener就绪后,会先接收到这个事件。

 

finishBeanFactoryInitialization(beanFactory)

通过上面的注释:Instantiate all remaining (non-lazy-init) singletons.

我们可以知道,这个方法初始化所有的非懒加载单例实例,代码很复杂,后面会开一个专题分析这段代码的。

 

finishRefresh()

从函数名可以知道这个是完成刷新,代码如下:

    protected void finishRefresh() 
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        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);
    

实际上它:

1. 清空了资源缓存

2. 初始化了生命周期处理器,用于处理Bean生命周期

3. 使用生命周期处理器传播刷新事件

4. 在Context内发布刷新事件

5. 将本Context注册到ListBeansView中

 

至此,Context的refresh分析完毕,下一部该分析Spring Boot的run进行了什么操作了。

以上是关于Spring context的refresh函数执行过程分析的主要内容,如果未能解决你的问题,请参考以下文章

07Spring源码-分析篇-refresh方法

Spring Boot启动过程

ObjectContext.Refresh()?

运行spring aop例子时,出现下面的错误,不知如何解决,看起来又不想异常?

解决java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh

Spring IoC源码解析之getBean