述
上文中了解了web容器的一个整体的启动流程, 在 createWebServer()
这个方法中,调用了 getWebServerFactory()
这个方法, 通过这个方法获取 webServerFactory
工厂, 就是去容器中找 ServletWebServerFactory
的实现类, 那么 ServletWebServerFactory
的实现类是什么时候被注入到容器中的, 下面来看一下 ServletWebServerFactory
工厂类加载的流程
源码跟踪
首先我们进入启动类的 @SpringBootApplication
注解看一下
进入这个注解
可以看到这里通过 @Import
注解导入了一个 AutoConfigurationImportSelector
, 我们进入这个类看一下
这里可以看到,这个类是实现的 DeferredImportSelector
这个类, 对于 @Import
注解的处理,我们之前在配置类解析的时候有说过了, 进入 @Import
注解处理的方法中,看一下具体的处理流程
@Import 处理
可以看到,这里会调用 DeferredImportSelectorHandler
的 handle
方法, 点进去
这里进来做了个判断, deferredImportSelectors
是肯定不为 null 的, 所以这里做的事情就是把传进来的 DeferredImportSelector
和当前的配置类,包装到一个 DeferredImportSelectorHolder
对象当中去,然后放到上面的 deferredImportSelectors
集合中去, 我们可以看一下 DeferredImportSelectorHolder
的构造方法
通过上面的处理流程我们可以看到这里只是把 DeferredImportSelector
的实现都包装起来添加到一个集合中去的, 并没有做实际的处理,那么这个集合是什么时候做处理的, 我们来看一下配置类解析最开始的 parse()
方法, 如下
这里在方法的最后会调用 DeferredImportSelectorHandler.process()
这个方法,这个方法就是去处理集合中的数据的
DeferredImportSelectorHandler$process
来具体看一下这个方法做的事情
这里主要是调用了两个方法,先循环调用 DeferredImportSelectorGroupingHandler.register()
这个方法, 然后调用 DeferredImportSelectorGroupingHandler.processGroupImports()
这个方法处理, 我们分别来看一下这两个方法都做了哪些事情
DeferredImportSelectorGroupingHandler$register
首先是第一个 getImportGroup()
方法, 这个方法在 AutoConfigurationImportSelector
这个实现中,返回的是 AutoConfigurationGroup.class
如图
接下来是往 groupings
里面put进去了一个key-value, key就是上面返回来的 group , 然后 value 是通过key计算出来的, 首先调用了 createGroup()
这个方法
这里主要是返回一个 Group
对象,然后赋值了一些其他属性, 最后又 new 了一个 DeferredImportSelectorGrouping
对象,看一下这个对象的构造
这里只是做了一个包装
总体而言,这个 DeferredImportSelectorGroupingHandler$register
方法就是获取一个 group , 然后下面的 DeferredImportSelectorGroupingHandler.processGroupImports()
这个方法会做具体的处理
DeferredImportSelectorGroupingHandler$processGroupImports
这里首先是循环 groupings 的 values ,就是上一部添加进去的 DeferredImportSelectorGrouping
对象, 然后调用他的 getImports()
方法获取一个集合,然后循环, 先看一下 getImports()
这个方法是怎么处理的
这里先会循环 deferredImports
这个集合,然后调用 this.group.process()
这个方法, 点进去,这里还是看 AutoConfigurationImportSelector
这个类的具体实现
这里的重点是 getAutoConfigurationEntry()
这个方法, 点进去
调用的方法比较多,首先这里的 getAttributes()
方法就是获取注解中的一些属性, 这里也就是 @EnableAutoConfiguration
这个注解的属性, 如下
我们这里并没有做这两个属性的配置,所以获取到的是空的, 然后进入下一个方法 getCandidateConfigurations()
这一步会获取 spring.factories
中的所有 EnableAutoConfiguration
这个类的实现, 然后下一个方法 removeDuplicates()
对上面获取到的集合做一个去重的操作
下面的几步都是针对需要过滤的配置类做一些处理,由于我们这里注解并没有配置,所以不会有需要忽略的类,这几个方法就不详细看了,然后是 filter()
这个方法
这个方法的作用主要是对上面获取到的类做一些过滤,通过 getAutoConfigurationImportFilters()
这个方法获取过滤器, 这个方法如下
上面这两部我们可以打个断点看一下
这里可以看到获取到的 attributes
都是空的, 然后 configurations
有124个, 接着往下执行
经过过滤之后只剩下 23 个了,回到上层看一下 grouping,getImports()
这个方法的具体返回
这里就是上一步获取到的 23 个配置类, 我们这里重点关注 ServletWebServerFactoryAutoConfiguration
,打开这个类看一下
这个类会通过 @Import
注解注入一系列的类, 这里我们进入 EmbeddedTomcat
这个类,如下
可以看到这里有几个 @Conditional
指定的条件, 第一个就是 @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
,然后是 @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
就是 @ConditionalOnClass
注解指定的类存在且 @ConditionalOnMissingBean
指定的类不存在的情况下, 这个配置类才会生效, 如果生效的话,就会执行下面的 @Bean
方法, 这个方法就是向容器注入 TomcatServletWebServerFactory
这个工厂类的
到这里整个工厂类的加载流程就完成了
总结
这里可能有点乱,可以打个断点把总体流程执行一遍,这里还是画个流程图来整理一下