写点什么

SpringBoot 源码学习系列之嵌入式 Servlet 容器

用户头像
极客good
关注
发布于: 刚刚

<artifactId>spring-boot-starter-web</artifactId>


<exclusions>


<exclusion>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-tomcat</artifactId>


</exclusion>


</exclusions>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-jetty</artifactId>


</dependency>


4、servlet 容器启动原理




ok,有了前面应用方面的学习之后,就可以简单跟一下 Springboot 是怎么对 servlet 容器进行自动配置的?内嵌的默认 Tomcat 容器是怎么样启动的?


从之前博客的学习,可以知道 Springboot 的自动配置都是通过一些 AutoConfiguration 类进行自动配置的,所以同理本博客也找一些对应的类,ServletWebServerFactoryAutoConfiguration 就是嵌入式 servlet 容器的自动配置类,简单跟一下其源码


@Configuration(proxyBeanMethods = false)


@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)


@ConditionalOnClass(ServletRequest.class)


@ConditionalOnWebApplication(type = Type.SERVLET)


@EnableConfigurationProperties(ServerProperties.class)//使 ServerProperties 配置类起效


@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,


ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,


ServletWebServerFactoryConfiguration.EmbeddedJetty.class,


ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })//@Import 是 Spring 框架的注解,作用是将对应组件加载到容器,这里关键的是 BeanPostProcessorsRegistrar,一个后置处理类


public class ServletWebServerFactoryAutoConfiguration {


@Bean


public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {


return new ServletWebServerFactoryCustomizer(serverProperties);


}


//Tomcat 的定制器类,起作用的条件是有 Tomcat 对应 jar 有引入项目的情况,默认是引入的,所以会执行 Tomcat 的 servletWeb 工厂定制类


@Bean


@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")


public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(


ServerProperties serverProperties) {


return new TomcatServletWebServerFactoryCustomizer(serverProperties);


}


....


//注册重要的后置处理器类 WebServerFactoryCustomizerBeanPostProcessor,在 ioc 容器启动的时候会调用后置处理器


public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {


private ConfigurableListableBeanFactory beanFactory;


//设置 ConfigurableListableBeanFactory


@Override


public void setBeanFactory(BeanFactory beanFactory) throws BeansException {


if (beanFactory instanceof ConfigurableListableBeanFactory) {


this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;


}


}


@Override


public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,


BeanDefinitionRegistry registry) {


if (this.beanFactory == null) {


return;


}


registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",


WebServerFactoryCustomizerBeanPostProcessor.class);


registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",


ErrorPageRegistrarBeanPostProcessor.class);


}


private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {


if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {


RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);


beanDefinition.setSynthetic(true);


registry.registerBeanDefinition(name, beanDefinition);


}


}


}


}


从自动配置类里,我们并不能很明确地理解自动配置是怎么运行的,只看重关键的一些信息点,比如注册了 Tomcat 的 ServletWebServer 工厂的定制器类,方法是 tomcatServletWebServerFactoryCustomizer,还有一个后置处理类 BeanPostProcessorsRegistrar,后置处理是 Spring 源码里是很关键的,所以这里可以继续点一下 TomcatServletWebServerFactoryCustomizer,Tomcat 的 webServer 工厂定制器类


也是一个 WebServerFactoryCustomizer 类型的类,从前面的应用学习,这个类是进行 servlet 容器的一些定制



这个是关键的方法,主要是拿 ServerProperties 配置类里的信息进行特定属性定制



所以,这里就可以知道 Tomcat 的配置是通过定制器类 TomcatServletWebServerFactoryCustomizer 进行定制的,其工厂类是 TomcatServletWebServerFactory


TomcatServletWebServerFactory 工厂类进行 Tomcat 对象的创建,必要参数的自动配置



ok,简单跟了一下源码之后,我们知道了 TomcatServletWebServerFactoryCustomizer 是 Tomcat 的定制器类,Tomcat 对象的创建是通过 TomcatServletWebServerFactory 类的,然后,有个疑问,这个定制器类是什么时候创建的?为什么一启动 Application 类,嵌入式的 Tomcat 也启动了?打成 jar 格式的 Springboot 项目,只要运行 jar 命令,不需要启动任何 servlet 容器,项目也是正常运行的?然后这个 BeanPostProcessorsRegistrar 后置处理类有什么作用?ok,带着这些疑问,我们还是用调试一下源码


如图,打断点调试,看看 Tomcat 定制器是怎么创建的?



定制器类被调用了,其对应的工厂类也会起作用,打个断点,看看工厂类是怎么调用的?



ok,启动 Application 类,在 idea 里调试,如图,可以跟着调用顺序,一点点跟源码,如图所示,调用了 Springbo


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


ot 的 run 方法



run 方法里的刷新上下文方法,refreshContext 其实也就是创建 ioc 容器,初始化 ioc 容器,并创建容器的每一个组件



这里注意到了,调用到了 ServletWebServerApplicationContext 类的 refresh 方法,ServletWebServerApplicationContext 类前面也介绍到了,这个类是一种特殊的 ApplicationContext 类,也就是一些 ioc 的上下文类,作用于 WebServer 类型的类



创建 webServer 类,先创建 ioc 容器,调用基类的 onRefresh 方法,然后再调用 createWebServer 方法



ioc 的 servletContext 组件没被创建的情况,调用 ServletWebServerFactory 类获取 WebServer 类,有 servletContext 的情况,直接从 ioc 容器获取



扫描 ioc 容器里是否有对应的 ServletWebServerFactory 类,TomcatServletWebServerFactory 是其中一种,通过调试,是有扫描到的,所以从 ioc 容器里将这个 bean 对应的信息封装到 ServletWebServerFactory 对象



接着是 ioc 容器创建 bean 的过程,这个一个比较复杂的过程,因为是单例的,所以是调用 singleObjects 进行存储



bean 被创建之后,调用了后置处理器,这个其实就是 Spring 的源码里的 bean 的创建过程,后置处理器是很关键的,在 bean 被创建,还没进行属性赋值时候,就调用了后置处理器



关键点,这里是检测是否有 WebServerFactory 工厂类,前面的调试发现已经有 Tomcat 的 WebServer 工厂类,所以是会调用后置处理器的



调用了 WebServerFactoryCustomizerBeanPostProcessor 这个后置处理类,然后拿到一个 WebServerFactoryCustomizer 定制器类,也就是 TomcatWebServerFactoryCustomizer,通过后置处理器调用定制方法 customize



然后 WebServerFactoryCustomizerBeanPostProcessor 这个后置处理器是什么注册的?往前翻 Springboot 的自动配置类,在这里找到了 WebServerFactoryCustomizerBeanPostProcessor 的注册



ok,继续调试源码,BeanWrapperImpl 创建 bean 实例



ok,Tomcat 定制器类被调用了,是通过后置处理器调用的



然后就是之前跟过的定制方法 customize 执行:



Tomcat 的 WebServer 工厂类创建 Tomcat 对象实例,进行属性配置,引擎设置等等



用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot源码学习系列之嵌入式Servlet容器