Spring Boot-20-web工厂类加载解析

上文中了解了web容器的一个整体的启动流程, 在 createWebServer() 这个方法中,调用了 getWebServerFactory() 这个方法, 通过这个方法获取 webServerFactory 工厂, 就是去容器中找 ServletWebServerFactory 的实现类, 那么 ServletWebServerFactory 的实现类是什么时候被注入到容器中的, 下面来看一下 ServletWebServerFactory 工厂类加载的流程

源码跟踪

首先我们进入启动类的 @SpringBootApplication 注解看一下

image

进入这个注解

image

可以看到这里通过 @Import 注解导入了一个 AutoConfigurationImportSelector , 我们进入这个类看一下

image

这里可以看到,这个类是实现的 DeferredImportSelector 这个类, 对于 @Import 注解的处理,我们之前在配置类解析的时候有说过了, 进入 @Import 注解处理的方法中,看一下具体的处理流程

@Import 处理

image

可以看到,这里会调用 DeferredImportSelectorHandlerhandle 方法, 点进去

image

这里进来做了个判断, deferredImportSelectors 是肯定不为 null 的, 所以这里做的事情就是把传进来的 DeferredImportSelector 和当前的配置类,包装到一个 DeferredImportSelectorHolder 对象当中去,然后放到上面的 deferredImportSelectors 集合中去, 我们可以看一下 DeferredImportSelectorHolder 的构造方法

image

通过上面的处理流程我们可以看到这里只是把 DeferredImportSelector 的实现都包装起来添加到一个集合中去的, 并没有做实际的处理,那么这个集合是什么时候做处理的, 我们来看一下配置类解析最开始的 parse() 方法, 如下

image

这里在方法的最后会调用 DeferredImportSelectorHandler.process() 这个方法,这个方法就是去处理集合中的数据的

DeferredImportSelectorHandler$process

来具体看一下这个方法做的事情

image

这里主要是调用了两个方法,先循环调用 DeferredImportSelectorGroupingHandler.register() 这个方法, 然后调用 DeferredImportSelectorGroupingHandler.processGroupImports() 这个方法处理, 我们分别来看一下这两个方法都做了哪些事情

DeferredImportSelectorGroupingHandler$register

image

首先是第一个 getImportGroup() 方法, 这个方法在 AutoConfigurationImportSelector 这个实现中,返回的是 AutoConfigurationGroup.class 如图

image

接下来是往 groupings 里面put进去了一个key-value, key就是上面返回来的 group , 然后 value 是通过key计算出来的, 首先调用了 createGroup() 这个方法

image

这里主要是返回一个 Group 对象,然后赋值了一些其他属性, 最后又 new 了一个 DeferredImportSelectorGrouping 对象,看一下这个对象的构造

image

这里只是做了一个包装

总体而言,这个 DeferredImportSelectorGroupingHandler$register 方法就是获取一个 group , 然后下面的 DeferredImportSelectorGroupingHandler.processGroupImports() 这个方法会做具体的处理

DeferredImportSelectorGroupingHandler$processGroupImports

image

这里首先是循环 groupings 的 values ,就是上一部添加进去的 DeferredImportSelectorGrouping 对象, 然后调用他的 getImports() 方法获取一个集合,然后循环, 先看一下 getImports() 这个方法是怎么处理的

image

这里先会循环 deferredImports 这个集合,然后调用 this.group.process() 这个方法, 点进去,这里还是看 AutoConfigurationImportSelector 这个类的具体实现

image

这里的重点是 getAutoConfigurationEntry() 这个方法, 点进去

image

调用的方法比较多,首先这里的 getAttributes() 方法就是获取注解中的一些属性, 这里也就是 @EnableAutoConfiguration 这个注解的属性, 如下

image

我们这里并没有做这两个属性的配置,所以获取到的是空的, 然后进入下一个方法 getCandidateConfigurations()

image

这一步会获取 spring.factories 中的所有 EnableAutoConfiguration 这个类的实现, 然后下一个方法 removeDuplicates() 对上面获取到的集合做一个去重的操作

image

下面的几步都是针对需要过滤的配置类做一些处理,由于我们这里注解并没有配置,所以不会有需要忽略的类,这几个方法就不详细看了,然后是 filter() 这个方法

image

这个方法的作用主要是对上面获取到的类做一些过滤,通过 getAutoConfigurationImportFilters() 这个方法获取过滤器, 这个方法如下

image

上面这两部我们可以打个断点看一下

image

这里可以看到获取到的 attributes 都是空的, 然后 configurations 有124个, 接着往下执行

image

经过过滤之后只剩下 23 个了,回到上层看一下 grouping,getImports() 这个方法的具体返回

image

这里就是上一步获取到的 23 个配置类, 我们这里重点关注 ServletWebServerFactoryAutoConfiguration ,打开这个类看一下

image

这个类会通过 @Import 注解注入一系列的类, 这里我们进入 EmbeddedTomcat 这个类,如下

image

可以看到这里有几个 @Conditional 指定的条件, 第一个就是 @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) ,然后是 @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) 就是 @ConditionalOnClass 注解指定的类存在且 @ConditionalOnMissingBean 指定的类不存在的情况下, 这个配置类才会生效, 如果生效的话,就会执行下面的 @Bean 方法, 这个方法就是向容器注入 TomcatServletWebServerFactory 这个工厂类的

到这里整个工厂类的加载流程就完成了

总结

这里可能有点乱,可以打个断点把总体流程执行一遍,这里还是画个流程图来整理一下

image