SpringBoot中Tomcat和SpringMVC整合源码分析

打印 上一主题 下一主题

主题 634|帖子 634|积分 1902

概述

​        SpringBoot中集成官方的第三方组件是通过在POM文件中添加组件的starter的Maven依赖来完成的。添加相关的Maven依赖之后,会引入具体的jar包,在SpringBoot启动的时候会根据默认自动装配的配置类的注入条件判断是否注入该自动配置类到Spring容器中。自动配置类中会创建具体的第三方组件需要的类 。Tomcat和SpringMVC都是通过这样的方式进行集成的。SpringBoot出现之前SpringMVC项目是直接部署在Tomcat服务器中的,Tomcat是一个符合Servlet标准的Web服务器,Tomcat单独作为一个可安装软件。这种方式下Tomcat是一个完整独立的web服务器,SpringMVC项目不能脱离Web服务器直接运行,需要先部署在Tomcat服务器的目录中才能运行。SpringBoot出现之后改变了这种方式,我们可以直接运行SpringBoot项目,因为SpringBoot中可以内嵌tomcat服务器,而tomcat也是java开发的。在启动SpringBoot项目的时候直接创建tomcat服务并且把SpringMVC的项目部署在tomcat服务中。
一、自动装配原理

​        在SpringBoot自动装配的程中,会加载/META-INF/factories文件中的以EnableAutoConfiguration为Key的配置类的字符串数组,在该类中会根据具体引入的服务器类进行创建具体的服务器对象。这些字符串数组是否真正加载进Spring容器,需要经过两方面的判断,
​       1.根据META-INF/spring-autoconfigure-metadata.properties文件中配置的规则判断是否需要过滤。
​                2.在org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass中会根据自动装配类的条件注解来判断是否进行自动加载。如果条件注解全部校验成功才会加载该配置类。
两种情况的底层校验逻辑都是一样的,都是通过调用OnWebApplicationCondition、OnClassCondition、OnBeanCondition的match方法进行判断。但是在processConfigurationClass方式的检查类型会更多,比如ConditionalOnMissingBean 等条件的检查。
条件注解注解备注OnWebApplicationCondition判断是否符合服务器类型OnClassCondition判断项目中是否存在配置的类OnBeanCondition判断Spring容器中是否注入配置的类二、内嵌式Tomcat注入

2.1自动注入配置类分析

1.ServletWebServerFactoryAutoConfiguration 配置类分析

​        1.META-INF/factories文件中以EnableAutoConfiguration为Key的配置类的字符串数组,其中 ServletWebServerFactoryAutoConfiguration 为创建Web服务器的自动配置类,根据META-INF/spring-autoconfigure-metadata.properties文件中配置的规则判断是否需要过滤,该文件关于ServletWebServerFactoryAutoConfiguration的配置描述如下,
  1. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration.ConditionalOnClass=javax.servlet.ServletRequest
  2. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration.ConditionalOnWebApplication=SERVLET
  3. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration.AutoConfigureOrder=-2147483648
复制代码
此配置说明需要在当前的项目中有javax.servlet.ServletRequest类并且WebApplication是SERVLET容器,才不会过滤。

  • 根据自动装配类的条件注解来判断是否进行自动加载,ServletWebServerFactoryAutoConfiguration 配置类的条件注解如下,
  1. @Configuration(proxyBeanMethods = false)
  2. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  3. // 判断是否有 ServletRequest 类
  4. @ConditionalOnClass(ServletRequest.class)
  5. // 判断 WebApplication 是 SERVLET 容器
  6. @ConditionalOnWebApplication(type = Type.SERVLET)
  7. @EnableConfigurationProperties(ServerProperties.class)
复制代码
此配置说明需要在当前的项目中有javax.servlet.ServletRequest类并且WebApplication是SERVLET容器,才会进行ServletWebServerFactoryAutoConfiguration 类的加载。
2.2注入逻辑具体分析


  • tomcat的starter依赖配置代码如下,
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-tomcat</artifactId>
  4.     <version>2.2.5.RELEASE</version>
  5.     <scope>compile</scope>
  6. </dependency>
复制代码

  • 添加Maven依赖配置后,会引入tomcat-embed-corejar包,其中有ServletRequest接口。代码截图如下,

SpringBoot的在创建服务器类型的时候是Servlet的,在创建SpringApplication的run方法中会调用createApplicationContext方法创建具体的AnnotationConfigServletWebServerApplicationContext类,该类继承了org.springframework.web.context.support.GenericWebApplicationContext类。OnWebApplicationCondition条件注解中就是通过判断是否有GenericWebApplicationContext类来检查是否是SERVLET类型的。

  • 所以添加完tomcat的starter依赖配置后,ServletWebServerFactoryAutoConfiguration所有的条件注解都会匹配成功 ,即会自动加载 ServletWebServerFactoryAutoConfiguration 自动装配类。该类会通过@Import注解导入3个内嵌服务器的实现类,这3个实现类的服务器都是Servlet标准的。代码如下,
  1. // 导入具体服务器类
  2. @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
  3.          ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
  4.          ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
  5.          ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
复制代码
三个Embeddedxxx表示相应的服务器实现类,每个服务器类都有自己的条件注解实现不同的加载逻辑,如果这里注入了多个web服务器,在服务器启动的时候会报错。EmbeddedTomcat类的代码如下,
  1. @Configuration(proxyBeanMethods = false)
  2. #当前工程下需要有Servlet、Tomcat UpgradeProtocol类
  3. @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
  4. #当前的Spring容器类不能有ServletWebServerFactory类型的Bean,搜索的是当前容器。
  5. @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
  6. static class EmbeddedTomcat {
  7.     @Bean
  8.     TomcatServletWebServerFactory tomcatServletWebServerFactory(
  9.         ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
  10.         ObjectProvider<TomcatContextCustomizer> contextCustomizers,
  11.         ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
  12.         // 创建 TomcatServletWebServerFactory ,是产生TomcatServletWebServer的工厂类
  13.         TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
  14.         factory.getTomcatConnectorCustomizers()
  15.             .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
  16.         factory.getTomcatContextCustomizers()
  17.             .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
  18.         factory.getTomcatProtocolHandlerCustomizers()
  19.             .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
  20.         return factory;
  21.     }
  22. }
复制代码
onStartup方法中会遍历 initializers 集合并且调用其onStartup()方法,而initializers包括了我们在调用getWebServer时传入的getSelfInitializer方法,该方法体的主要业务逻辑上面已经讲了(请看本章的第5点),就是给传进去的servletContext添加当前Spring容器中注入的SpringMVC的DispatchServlet类。

  • 最后tomcat完成初始化,会监听一个具体的端口。至此,tomcat启动的过程已经把SpringMVC的DispatchServlet类添加到了tomcat的servletContext对象中。当请求进来Web服务器的时候会转到DispatchServlet中。DispatchServlet的整个初始化过程这里不细讲了,请参考 SpringMVC请求流程源码分析 文章。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表