Spring Boot Web容器
Web应用开发是企业开发的重要领域,Spring Boot 1.X的Web容器管理方式基于Servlet容器技术栈。Servlet容器主要基于同步阻塞I/O架构,HTTP请求和线程是一对一的关系,主要是TPR模型,即一个请求对应一个线程。主要的业务逻辑也是基于命令式的编程模式。以Spring MVC框架为主,Web容器方面以Tomcat为主,也可以通过自动配置功能改为Jetty/UnderTow容器。
Spring Boot 2.X主要基于异步非阻塞I/O架构,HTTP请求基于收敛的线程模型,网络层使用基于Reactor的I/O多路复用模式,业务逻辑基于函数式编程模式,以Spring WebFlux为主要框架。在Web容器方面可以基于Servlet 3.0的异步模式,默认情况下使用Netty作为容器。本节我们主要以Spring Boot 1.X讲解嵌入式Web容器的启动和加载原理,在进阶篇的响应式编程中将介绍Spring 5及Spring Boot 2.X的响应式框架WebFlux对Web应用服务的支持。
Spring Boot Web容器配置
Spring Boot对Web项目的支持主要是Spring Boot对Spring MVC框架的继承。Spring MVC框架是一个基于Servlet容器标准的Web容器框架实现,Spring Boot向Spring MVC提供开箱即用的Starter:spring�boot-starter-web。
Spring Boot应用中利用自动配置功能,只需要在pom.xml文件中加入下面的Web依赖,就可以直接启动一个Web服务:
Spring Web MVC 框 架 使 用 特 定 的 @Controller 或 者@RestController 注 解 的 Bean 作 为 处 理 HTTP 请 求 的 端 点 , 通 过@RequestMapping注解将控制器中的方法与HTTP请求进行映射,示例如下:
Spring Boot为Spring MVC提供了自动配置功能,包含如下主要配置特性。
● 自动配置ViewResolver引入
ContentNegotiatingViewResolver组件功能。示例:在应用中添加ViewResolver组件用来匹配HTML静态页面,如果没有匹配成功,则返回false,由其他ViewResolver继续尝试匹配。ContentNegotiatingViewResolver会组合所有的视图解析器,代码如下。
● 自动注册Converter、GenericConverter、Formatter Bean。
示例:将页面提交数据转化为后台数据,实现格式化,代码如下。
● 对HttpMessageConverters的支持。
示例:Spring Boot可以为HttpMessageConverters类添加自定义转换类,通过这种方式可以将所有的HttpMessageConverters的Bean添加到Converter列表,覆盖默认的转换器列表,代码如下。
● 自动注册MessageCodeResolver。
● 自动使用ConfigurableWebBindingInitializer Bean。
● 使用WebMvcConfigurerAdapter类型的Bean来定制化配置。
默认情况下,Spring Boot 会以 /src/main/resources/static 作为查找静态资源的文件路径,如果想自定义静态资源映射目录,需要重写 addResourceHandlers 来添加指定路径,重写 addResourceLocations 来指定静态资源路径。
总之,我们可以根据自己的意愿,对默认的Spring MVC的组件配置加以修改,方法也很简单,通过在IoC容器中注册新的同类型Bean来替换即可。如果你希望完全接管Spring MVC的所有相关配置,可以添加自己的@Configuration,并使用@EnableWebMvc注解实现定制化配置。
JAX-RS和Jersey框架
如果你喜欢JAX-RS和REST风格的编程模型,可以使用下面的Starter替代Spring MVC框架,Spring支持Jersey 1.X和Jersey 2.X等技术框架。这里我们只介绍Spring Boot对Jersey 2.X的支持,在pom.xml文件中加入下面的依赖:
Spring Boot对Jersey的配置有三种主要方式。在开始不同的配置方式前,我们注册一个端点对象资源,示例代码如下:
● 第一种方式,创建一个自定义的ResourceConfig:
● 第二种方式,返回一个ResourceConfig类型的@Bean:
● 第三种方式,配置一组ResourceConfigCustomizer对象。
Spring Boot提供了ResourceConfigCustomizer接口,让我们更灵活地对ResourceConfig对象进行配置。要使用该接口,我们需要先注释掉前面两节中提到的相关代码,然后创建一个类:
默认情况下 , Jersey 将以 Servlet 的形式注册一个 ServletRegistrationBean 类型的 @Bean 。 它 的 名 字 为 jerseyServletRegistration,该 Servlet 默认会延迟初始化。
你可以通过 spring.jersey.servlet.load-on-startup 自定义配置Jersey组件。通过创建相同名字的 Bean,可以禁用或覆盖框架默认的 Bean。设置 spring.jersey.type=filter 可以使用 Filter 的形式代替 Servlet , 相应的 @Bean 类 型 变 为 jerseyFilter-Registration , 该Filter有一个@Order属性,你可以通过 spring.jersey.filter.order 设置该属性 。 Servlet 和 Filter 在 注 册 时 都 可 以 使 用 spring.jersey.init.* 定义一个属性集合并将其传递给init参数进行初始化。
内嵌容器的配置
Spring Boot 的 另 一 大 特 性 就 是 支 持 内 嵌 的 Web 容 器 , 包 括Tomcat、Jetty和UnderTow服务器,大多数开发者只需要使用合适的Starter来获取一个完全配置好的实例即可,内嵌服务器默认监听8080端口的HTTP请求。spring-boot-starter-web默认使用Tomcat作为Web容器,你可以在pom.xml中去除
spring-boot-starter-tomcat依赖,然后 引 入 spring-boot-starter-jetty 或 者 spring-boot-starter�undertow模块作为替代Web容器方案。Starter还提供了以“server.”为前缀的配置项对嵌入式容器配置进行修改。配置项的加载和定制化钩子加载过程如下。
1.自动化配置嵌入式容器
2.初始化TomcatEmbeddedServletContainerFactory的Bean对象
3.定制化Bean扩展逻辑
EmbeddedServletContainerCustomizerBeanPostProcessor 在加载 Bean 后开始初始化配置项 PostProcessor 的处理逻辑:
4.配置文件加载
从配置文件中,你可以加载配置文件对象的配置值。如果配置文件中没有相关配置项,将使用默认代码设定配置。
5.Web容器定制化
如果你需要对Web容器进行更深入的定制,可以使用对应的Factory自动化配置Tomcat容器,它是初始化的关键流程和步骤,代码示例如下:
下图是Spring Boot启动过程中Tomcat容器完成自动配置的类图结构。我们在最新的Spring Boot下查看Tomcat的相关配置,发现有两个自动装配类,分别包含了三个定制器,还有一个工厂类。