述
上文中了解了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 这个工厂类的
到这里整个工厂类的加载流程就完成了
总结
这里可能有点乱,可以打个断点把总体流程执行一遍,这里还是画个流程图来整理一下