Spring中的refreshContext源码分析
前言
在SpringBoot启动流程中,主要的两个阶段是初始化SpringApplication对象以及SpringApplication.run方法执行的内容
今天主要细讲的是SpringApplication.run中的刷新容器refreshContext方法
refreshContext()
还是老办法,先梳理它的大体流程,将不太重要的舍去。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... // Prepare the bean factory for use in this context. //设置beanFacotry 和加载一些特殊bean的处理类, prepareBeanFactory(beanFactory); // 一些web项目的bean处理类 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //重要,唤醒 BeanFactoryPostProcessor的实现类 invokeBeanFactoryPostProcessors(beanFactory); ... // Register bean processors that intercept bean creation. //重要,将BeanPostProcessor的bean定义注册进来 registerBeanPostProcessors(beanFactory); ... // Initialize event multicaster for this context. //再次创建一个广播器 initApplicationEventMulticaster(); ... // Check for listener beans and register them. //注册listener到上述的心广播器中 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //重要,创建单例bean finishBeanFactoryInitialization(beanFactory); ... } }
那么整体上就分为一下几步
- 对beanFacotry进行设置
- 对benFactory在做一些定制处理(比如加载一些web容器对bean的处理类)
- 唤醒beanFactoryPostProcessor的一些列实现类
- 创建一个新广播器
- 将Listener加入到这个新广播器中(注意,这的Listener将会比我们上一篇所说的多的多,至于原因 在唤醒那一步里面)
- 将所有找到的单例类,都创建处理(这步内容也比较多,对于加载Bean的分析 将新启一篇文章进行说明)
prepareBeanFactory()
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //添加了一个BeanPostProcessor实例ApplicationContextAwareProcessor // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); //指定特定依赖的返回结果 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. //添加了一个BeanPostProcessor实例ApplicationListenerDetector beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); ... }
老办法 ,逐一分析。
第一步,添加了一个BeanPostProcessor实例ApplicationContextAwareProcessor
ApplicationContextAwareProcessor //这个bean处理器就是在实现了 EnvironmentAware.class EmbeddedValueResolverAware.class ResourceLoaderAware.class ApplicationEventPublisherAware.class MessageSourceAware.class ApplicationContextAware.class //的类实例化之前唤醒对应的接口方法
指定特定依赖的返回结果添加了一个BeanPostProcessor实例ApplicationListenerDetector
这个实例主要是检查bean是否实现了ApplicationListener,如果实现了就将它添加到监听器集合中
前面我们说了也可以通过spring.factories这个文件添加ApplicationListenr
这里又提供了一种方式,但是这种通过ApplicationListenerDetector来加载的方式 会让listener丢失一部分事件(因为在没有加载Bean之前还有很多事件),如果需要监听非常前面的事件,还是要通过spring.factories这个文件添加
这里都是讲处理类加载进来,并没有执行对应方法。真正访问还在后面,前面只是准备阶段
invokeBeanFactoryPostProcessors()
唤醒所有的BeanFactoryPostProcessor实例 ,这个与下面的registerBeanPostProcessor将会以独立的章节来分析(原因还是那个原因。。。 里面的内容有点多)。
registerBeanPostProcessor()
将BeanPostProcessor实例注册进来
registerListeners()
protected void registerListeners() { // Register statically specified listeners first //加载老的listener for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } //加载新的listenner // 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注册到新的广播器中,分步走。
- 加载老的listener,也就是我们最开始通过spring.factories加载进来的监听器
- 加载通过ApplicationListenerDetector注册进来的监听器
- 发送默认事件(就是表明这个时间节点的事件)到监听器中
完成bean的初始化,这个会单独形成一个章节,与getBean流程一起讲解
总结
- 准备BeanFacotry
- BeanFacotry准备完毕
- 对BeanFacotryPostProcessor进行唤醒(因为BeanFactory准备完毕了嘛)
- 注册BeanPostProcessor(因为接下来我们要实例化Bean嘛)
- 对单例Bean进行实例化
你看,逻辑清晰,前后有因果,一下就把整体流程给理顺了,而且出乎意料的合理。
到此这篇关于Spring中的refreshContext源码分析的文章就介绍到这了,更多相关refreshContext源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例
本篇文章主要介绍了struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例,具有一定的参考价值,有兴趣的可以了解一下。2017-01-01Java调用参数类型是application/x-www-form-urlencoded的API问题
在使用Postman进行接口测试时,对于POST请求,需将请求头设置为application/x-www-form-urlencoded,并将参数转为String类型,通常在GET请求中,参数直接拼接在URL后,本文通过具体实例,详细讲解了参数处理的方法,适合API开发者参考2024-09-09
最新评论