SpringBoot是怎么让内置Tomcat在启动时加载过滤器的?
初始化完Spring对象容器后,创建并启动WebServer。
Tomcat获取Server先获取Service,把Service放入Server中后再返回。
Tomcat获取Host先获取Engine,获取Engine先获取Service和Host,将Service用来处理所有请求的引擎容器设置为Engine,将Host放入Engine这个容器的子容器集合中。
将上下文初始化器配置到【【【【【Tomcat内的】Server下的】Service的】容器Engine下的】Host的子容器中的】TomcatEmbeddedContext内的】容器初始化器TomcatStarter。其中Engine、Host、TomcatEmbeddedContext都是接口Container的实现类。
在对TomcatEmbeddedContext进行配置的时候,配置了两个初始化器集合。先将从Sring容器中获取的用来注册过滤器的ServletContextInitializer集合放入TomcatStater的initializers属性中。而TomcatStater本身就是个用来初始化容器的ServletContainerInitializer,再将其加入TomcatEmbeddedContext下用来初始化的initializers属性中。
WebServer为TocatWebServer,实例化后立即初始化,并使其tomcat启动。
Tomcat使其Server启动。
Server使其Service启动。
Service使其Engine启动。
Engine启动其包含的子容器,即初始化时加入的Host。启动过程为,通过子容器构建一个接口Callable的实现类StartChild的实例。
之前将Host加入Engine的子容器集合。
然后在线程池AbstractExecutorService的submit方法中,异步执行由StartChild构建的FutureTask。
由于StartChild实现了Callable接口,所以在被线程池通过FutureTask启动时,会调用器call()方法。此时赋值为Host的属性child将被启动,因为Host实现了接口Container和Lifecycle。
Host接下来又会执行它生命周期的启动过程。
通过线程池、StartChild和FutureTask启动Host的子容器TomcatEmbeddedContext。
之前将TomcatEmbeddedContext加入Host的子容器集合中。
TomcatEmbeddedContext开始启动。
从属性initializers中依次取出容器初始化器进行启动,并传入Tomcat的上下文ApplicationContext的ApplicationContextFacade。
第一个要启动的就是之前放入的TomcatStater。
TomcatStarter的启动过程就是让其所拥有的上下文初始化器启动起来。
而它拥有的上下文初始化器就是Spring容器中通过lambda表达式实现的ServletContextInitializer的匿名类,它的方法onStartup()将会执行ServletWebServerApplicationContext的方法selfInitialize()。
接下来就是先通过方法getServletContextInitializerBeans()从Spring容器中获取到用来注册过滤器的ServletContextInitializer即FilterRegistrationBean,当然也包含用来注册其它Bean的初始化器。然后调用这些上下文初始化器的方法onStartup(),进行启动并将过滤器添加到ApplicationContextFacade中。