5.7 Tomcat 与 Spring 集成


文档摘要

5.7 Tomcat 与 Spring 集成 5.7 Tomcat 与 Spring 集成 5.7.1 集成概述 Tomcat 负责处理 HTTP 请求,管理 Servlet 生命周期,并提供 Web 应用运行的基础环境。Spring 框架则负责管理应用组件,处理业务逻辑,提供事务管理、安全控制等企业级服务。Tomcat 与 Spring 的集成,核心在于让 Spring 容器接管 Web 应用组件的生命周期管理和依赖注入,从而实现更清晰的架构分层和更高效的开发模式。 集成的主要目标: 依赖注入 (DI): Spring 容器负责创建和管理应用中的 Bean,包括 Controller、Service、Repository 等组件,并自动注入它们之间的依赖关系,降低组件之间的耦合度。

5.7 Tomcat 与 Spring 集成

5.7 Tomcat 与 Spring 集成

5.7.1 集成概述

Tomcat 负责处理 HTTP 请求,管理 Servlet 生命周期,并提供 Web 应用运行的基础环境。Spring 框架则负责管理应用组件,处理业务逻辑,提供事务管理、安全控制等企业级服务。Tomcat 与 Spring 的集成,核心在于让 Spring 容器接管 Web 应用组件的生命周期管理和依赖注入,从而实现更清晰的架构分层和更高效的开发模式。

集成的主要目标:

  • 依赖注入 (DI): Spring 容器负责创建和管理应用中的 Bean,包括 Controller、Service、Repository 等组件,并自动注入它们之间的依赖关系,降低组件之间的耦合度。

  • 控制反转 (IoC): 将对象的创建和管理权从应用程序代码转移到 Spring 容器,应用程序只需要关注业务逻辑,无需关心对象的创建和生命周期。

  • AOP 支持: 利用 Spring AOP 实现横切关注点的集中管理,例如日志记录、性能监控、事务管理等,提高代码的模块化和可维护性。

  • Spring MVC 框架: 使用 Spring MVC 框架构建 Web 层,简化请求处理流程,实现清晰的 MVC 架构。

  • 事务管理: 利用 Spring 的事务管理功能,简化数据库事务的处理,保证数据的一致性。

  • 资源管理: Spring 提供了方便的资源管理接口,可以轻松访问各种资源,例如文件、数据库连接等。

集成方式:

Tomcat 与 Spring 的集成主要通过以下两种方式实现:

  1. 传统的 WAR 包部署方式 (web.xml 配置): 这是最经典的方式,通过在 web.xml 配置文件中配置 ContextLoaderListenerDispatcherServlet 来启动 Spring 容器和 Spring MVC。

  2. 嵌入式 Tomcat (Spring Boot): Spring Boot 提供了嵌入式 Tomcat 的支持,可以将 Tomcat 打包到可执行的 JAR 文件中,简化部署和配置。

本章节将重点介绍传统的 WAR 包部署方式,并简要介绍 Spring Boot 嵌入式 Tomcat 的集成。

5.7.2 传统 WAR 包部署集成详解

传统的 WAR 包部署方式,需要手动配置 web.xml 文件,来引导 Tomcat 加载 Spring 容器和 Spring MVC 组件。以下是详细的步骤和配置说明。

5.7.2.1 配置 ContextLoaderListener

ContextLoaderListener 是 Spring 提供的 Servlet 监听器,负责在 Web 应用启动时创建 Spring 的 根 Web 应用上下文 (Root Web Application Context)。这个根上下文通常包含应用中通用的 Bean,例如 Service 层、Repository 层、数据源、事务管理器等。

配置 web.xml:

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>

配置详解:

  • <listener>: 声明一个 Servlet 监听器。

  • <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>: 指定监听器的类为 ContextLoaderListener,这是 Spring 提供的用于启动根 Web 应用上下文的关键监听器。

  • <context-param>: 定义 Web 应用的上下文参数。

  • <param-name>contextConfigLocation</param-name>: 指定上下文参数的名称为 contextConfigLocation,Spring ContextLoaderListener 会读取这个参数来确定 Spring 配置文件的位置。

  • <param-value>classpath:applicationContext.xml</param-value>: 指定 Spring 配置文件的位置为 classpath:applicationContext.xml,这意味着 Spring 会在类路径下查找名为 applicationContext.xml 的配置文件。你可以根据实际情况修改这个路径,例如可以使用逗号分隔多个配置文件,或者使用文件系统路径。

工作原理 (Graph TD 图):

图解说明:

  1. Tomcat 启动 Web 应用时,首先加载 web.xml 配置文件。

  2. Tomcat 解析 web.xml,发现配置了 ContextLoaderListener 监听器。

  3. Tomcat 启动 ContextLoaderListener

  4. ContextLoaderListener 读取 contextConfigLocation 上下文参数。

  5. ContextLoaderListener 根据 contextConfigLocation 指定的路径加载 Spring 配置文件 applicationContext.xml

  6. Spring 容器根据 applicationContext.xml 的配置创建 根 Web 应用上下文 (Root Web Application Context)

  7. 根上下文创建完成后,ContextLoaderListener 完成启动,Root Context 准备就绪。

5.7.2.2 配置 DispatcherServlet

DispatcherServlet 是 Spring MVC 框架的核心 Servlet,负责接收所有的 HTTP 请求,并将请求分发到相应的 Handler (通常是 Controller 中的方法) 进行处理。DispatcherServlet 会创建自己的 Web 应用上下文 (Web Application Context),这个上下文是 根 Web 应用上下文 (Root Web Application Context) 的子上下文,它可以访问根上下文中的 Bean。Web Application Context 通常包含 Web 层相关的 Bean,例如 Controller、ViewResolver、HandlerMapping 等。

配置 web.xml:

<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

配置详解:

  • <servlet>: 声明一个 Servlet。

  • <servlet-name>dispatcherServlet</servlet-name>: 指定 Servlet 的名称为 dispatcherServlet,这个名称可以自定义,但在 <servlet-mapping> 中需要保持一致。

  • <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>: 指定 Servlet 的类为 DispatcherServlet,这是 Spring MVC 框架提供的核心 Servlet。

  • <init-param>: 定义 Servlet 的初始化参数。

  • <param-name>contextConfigLocation</param-name>: 指定初始化参数的名称为 contextConfigLocationDispatcherServlet 会读取这个参数来确定 Spring MVC 配置文件的位置。

  • <param-value>classpath:spring-mvc.xml</param-value>: 指定 Spring MVC 配置文件的位置为 classpath:spring-mvc.xml,这意味着 Spring 会在类路径下查找名为 spring-mvc.xml 的配置文件。你可以根据实际情况修改这个路径。

  • <load-on-startup>1</load-on-startup>: 指定 Servlet 在 Tomcat 启动时立即加载,数值越小,启动优先级越高。通常将 DispatcherServletload-on-startup 设置为 1,确保它在 Web 应用启动时尽早加载。

  • <servlet-mapping>: 定义 Servlet 的 URL 映射。

  • <servlet-name>dispatcherServlet</servlet-name>: 指定要映射的 Servlet 名称,需要与 <servlet> 中定义的 <servlet-name> 一致。

  • <url-pattern>/</url-pattern>: 指定 URL 匹配模式为 /,这意味着所有请求都会被 dispatcherServlet 拦截处理。 你可以根据实际需求调整 URL 匹配模式,例如 /api/* 只拦截以 /api/ 开头的请求。

工作原理 (Graph TD 图):

图解说明:

  1. Tomcat 接收到 HTTP 请求。

  2. Tomcat 根据 <servlet-mapping> 配置的 URL 模式进行 Servlet 匹配。

  3. 如果请求 URL 匹配到 dispatcherServlet 的 URL 模式 (例如 /),则将请求交给 dispatcherServlet 处理。

  4. DispatcherServlet 启动并读取 contextConfigLocation 初始化参数。

  5. DispatcherServlet 根据 contextConfigLocation 指定的路径加载 Spring MVC 配置文件 spring-mvc.xml

  6. Spring 容器根据 spring-mvc.xml 的配置创建 Web 应用上下文 (Web Application Context),它是 Root Web Application Context 的子上下文。

  7. Web Application Context 创建完成后,DispatcherServlet 准备就绪。

  8. DispatcherServlet 根据请求信息,例如 URL、请求方法等,将请求分发到相应的 Handler (Controller 中的方法) 进行处理。

5.7.2.3 Spring 配置文件 (applicationContext.xmlspring-mvc.xml)

web.xml 中配置了 ContextLoaderListenerDispatcherServlet 后,还需要创建相应的 Spring 配置文件,即 applicationContext.xmlspring-mvc.xml

applicationContext.xml (Root Web Application Context 配置):

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扫描 Service 和 Repository 组件 --> <context:component-scan base-package="com.example.service, com.example.repository"/> <!-- 数据源配置 (示例) --> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- 事务管理器配置 (示例) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 其他通用 Bean 配置 ... --> </beans>

配置详解:

  • <context:component-scan base-package="com.example.service, com.example.repository"/>: 配置组件扫描,Spring 会自动扫描指定包及其子包下的类,并将带有 @Service, @Repository, @Component 等注解的类注册为 Bean。你需要将 base-package 修改为你的 Service 和 Repository 组件所在的包路径。

  • <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> ... </bean>: 配置数据源 Bean,这里使用了 Apache DBCP 连接池作为示例。你需要根据实际使用的数据库和连接池进行配置。

  • <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> ... </bean>: 配置事务管理器 Bean,用于声明式事务管理。你需要根据实际使用的事务管理器进行配置。

  • 其他通用 Bean 配置: 可以在这个文件中配置其他通用的 Bean,例如工具类、配置类等。

spring-mvc.xml (Web Application Context 配置):

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 扫描 Controller 组件 --> <context:component-scan base-package="com.example.controller"/> <!-- 启用 Spring MVC 注解驱动 --> <mvc:annotation-driven/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 静态资源处理 (可选) --> <mvc:default-servlet-handler/> <!-- 其他 Web 层 Bean 配置 ... --> </beans>

配置详解:

  • <context:component-scan base-package="com.example.controller"/>: 配置组件扫描,Spring 会自动扫描指定包及其子包下的类,并将带有 @Controller, @RestController 等注解的类注册为 Bean。你需要将 base-package 修改为你的 Controller 组件所在的包路径。

  • <mvc:annotation-driven/>: 启用 Spring MVC 注解驱动,激活 Spring MVC 的常用功能,例如 HandlerMapping、HandlerAdapter、HttpMessageConverter 等,支持使用注解进行请求映射、参数绑定、数据转换等。

  • <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> ... </bean>: 配置视图解析器,用于将 Controller 返回的逻辑视图名解析为实际的视图文件路径。这里使用了 InternalResourceViewResolver,它会将逻辑视图名解析为 /WEB-INF/views/ 目录下的 JSP 文件。你需要根据实际使用的视图技术和文件路径进行配置。

  • <mvc:default-servlet-handler/>: 配置静态资源处理器,用于处理静态资源请求,例如 CSS, JavaScript, 图片等。配置后,Spring MVC 会将静态资源请求转发给 Servlet 容器的默认 Servlet 处理,从而可以访问 Web 应用根目录下的静态资源。

  • 其他 Web 层 Bean 配置: 可以在这个文件中配置其他 Web 层相关的 Bean,例如 Interceptor, HandlerExceptionResolver 等。

5.7.2.4 上下文层级关系

在传统的 WAR 包部署集成中,Spring 会创建两个 Web 应用上下文:

  • Root Web Application Context (根上下文):ContextLoaderListener 创建,通过 applicationContext.xml 配置,包含应用中通用的 Bean。

  • Web Application Context (Web 上下文):DispatcherServlet 创建,通过 spring-mvc.xml 配置,包含 Web 层相关的 Bean。

上下文层级关系 (Graph TD 图):

图解说明:

  • Web Application Context 是 Root Web Application Context 的子上下文。 这意味着 Web Application Context 可以访问 Root Web Application Context 中定义的 Bean,而 Root Web Application Context 无法访问 Web Application Context 中定义的 Bean。

  • 父子上下文的隔离性有助于更好地组织和管理 Bean。 通常将通用的 Bean (例如 Service, Repository, 数据源, 事务管理器) 放在 Root Web Application Context 中,将 Web 层相关的 Bean (例如 Controller, ViewResolver, HandlerMapping) 放在 Web Application Context 中。

访问父上下文 Bean:

在 Web Application Context 中,可以通过 Spring 的依赖注入机制直接访问父上下文 (Root Web Application Context) 中定义的 Bean。例如,在 Controller 中注入 Service Bean:

@Controller public class MyController { @Autowired private MyService myService; // 注入 Root Context 中的 Service Bean // ... }

Spring 会首先在当前的 Web Application Context 中查找 MyService Bean,如果找不到,则会向上查找父上下文 (Root Web Application Context),并在父上下文中找到 MyService Bean 并注入。

5.7.3 代码实践示例

以下是一个简单的 Spring MVC Web 应用示例,演示 Tomcat 与 Spring 的传统 WAR 包部署集成。

项目结构:

my-webapp/ ├── src/main/java/ │ └── com/example/ │ ├── controller/ │ │ └── HelloController.java │ └── service/ │ └── HelloService.java ├── src/main/resources/ │ ├── applicationContext.xml │ └── spring-mvc.xml └── src/main/webapp/ ├── WEB-INF/ │ ├── views/ │ │ └── hello.jsp │ └── web.xml └── index.jsp

代码示例:

HelloService.java (Service 组件):

package com.example.service; import org.springframework.stereotype.Service; @Service public class HelloService { public String getHelloMessage() { return "Hello, Spring and Tomcat!"; } }

HelloController.java (Controller 组件):

package com.example.controller; import com.example.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HelloController { @Autowired private HelloService helloService; @GetMapping("/hello") public String hello(Model model) { String message = helloService.getHelloMessage(); model.addAttribute("message", message); return "hello"; // 逻辑视图名 "hello" } }

hello.jsp (View 视图):

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Spring MVC</title> </head> <body> <h1>${message}</h1> </body> </html>

index.jsp (首页):

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Welcome</title> </head> <body> <a href="hello">Say Hello</a> </body> </html>

applicationContext.xml (Root Context 配置):

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.example.service"/> </beans>

spring-mvc.xml (Web Context 配置):

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.example.controller"/> <mvc:annotation-driven/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans>

web.xml (Web 应用配置):

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- 配置 ContextLoaderListener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 配置 DispatcherServlet --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>

部署和运行:

  1. 将项目打包成 WAR 文件 (例如 my-webapp.war)。

  2. 将 WAR 文件部署到 Tomcat 的 webapps 目录下。

  3. 启动 Tomcat 服务器。

  4. 在浏览器中访问 http://localhost:8080/my-webapp/http://localhost:8080/my-webapp/hello 即可运行示例应用。

5.7.4 Spring Boot 嵌入式 Tomcat 集成 (简述)

Spring Boot 提供了更便捷的 Tomcat 与 Spring 集成方式,它使用嵌入式 Tomcat,无需手动配置 web.xml 和部署 WAR 包。Spring Boot 通过自动配置和约定大于配置的原则,简化了集成过程。

主要特点:

  • 无需 web.xml: Spring Boot 应用不需要 web.xml 文件,配置可以通过注解、属性文件或 Java 代码完成。

  • 嵌入式 Tomcat: Spring Boot 将 Tomcat 打包到可执行的 JAR 文件中,可以直接运行 JAR 文件启动 Web 应用,无需单独部署 Tomcat。

  • 自动配置: Spring Boot 会根据项目依赖和配置自动配置 Spring MVC, Tomcat 等组件,减少手动配置工作。

  • 简化部署: Spring Boot 应用可以打包成可执行的 JAR 文件,部署非常简单,只需运行 java -jar my-springboot-app.jar 即可。

集成方式:

在 Spring Boot 项目中,只需要添加 spring-boot-starter-web 依赖,Spring Boot 就会自动配置嵌入式 Tomcat 和 Spring MVC。

pom.xml (Maven 依赖):

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>

示例 Spring Boot 应用:

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class MySpringBootApplication { public static void main(String[] args) { SpringApplication.run(MySpringBootApplication.class, args); } @GetMapping("/hello") public String hello() { return "Hello, Spring Boot Embedded Tomcat!"; } }

运行:

  1. 使用 Maven 或 Gradle 构建项目。

  2. 运行生成的 JAR 文件 (例如 java -jar my-springboot-app.jar)。

  3. 在浏览器中访问 http://localhost:8080/hello 即可运行示例应用。

Spring Boot 嵌入式 Tomcat 集成更加简洁高效,是现代 Web 应用开发的主流选择。

5.7.5 高级特性与最佳实践

  • Servlet 容器定制: Tomcat 提供了丰富的配置选项,可以根据应用需求定制 Servlet 容器的行为,例如端口号、线程池、连接器、SSL 配置等。Spring Boot 也允许对嵌入式 Tomcat 进行定制化配置。

  • Servlet 组件注册: 除了 DispatcherServlet,还可以将自定义的 Servlet、Filter、Listener 注册到 Tomcat 中,并与 Spring 容器集成,实现更灵活的 Web 组件扩展。

  • 性能优化: 在集成 Tomcat 和 Spring 时,需要关注性能优化,例如合理配置 Tomcat 线程池、数据库连接池、缓存策略、异步请求处理等,以提升应用的性能和吞吐量。

  • 安全性: Tomcat 和 Spring 都提供了丰富的安全特性,例如 SSL/TLS 加密、身份认证、授权管理、防止 CSRF/XSS 攻击等。在集成时需要配置和启用相应的安全功能,保障应用的安全。

  • 监控与管理: Tomcat 提供了 JMX 监控接口,可以监控 Tomcat 的运行状态和性能指标。Spring Boot Actuator 也提供了丰富的监控和管理端点,可以方便地监控和管理 Spring Boot 应用。


发布者: 作者: 转发
评论区 (0)
U