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函数执行过程分析的主要内容,如果未能解决你的问题,请参考以下文章
运行spring aop例子时,出现下面的错误,不知如何解决,看起来又不想异常?
解决java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh