Spring 在 Web 应用中的集成:从原理到配置 在 Java Web 开发中,Spring 框架通过与 Servlet 容器的整合,实现了 IOC 容器的自动初始化和管理。与普通 Java 应用不同,Web 应用没有 main 方法,而是通过 Servlet 容器(如 Tomcat)启动,因此需要借助 Servlet 监听器在容器启动时初始化 Spring IOC 容器。本文将详细解析 Spring 与 Web 应用的整合原理及配置方式。
Web 应用中 Spring 的核心挑战 Web 应用的生命周期由 Servlet 容器(如 Tomcat)管理,其启动流程与普通 Java 应用截然不同:
普通 Java 应用:通过 main 方法手动初始化 Spring 容器(如 new AnnotationConfigApplicationContext(...));
Web 应用:由 Servlet 容器启动,需在容器启动阶段自动创建 Spring IOC 容器,并在整个应用生命周期中共享。
核心需求 :在 Servlet 容器启动时初始化 Spring 容器,并将其存储在全局作用域(ServletContext)中,供后续的 Servlet、Filter 等组件使用。
整合原理:基于 ServletContextListener Servlet 规范提供了 ServletContextListener 接口,用于监听 ServletContext(Web 应用全局上下文)的创建和销毁。Spring 正是利用这一机制,在 ServletContext 初始化时(即 Web 应用启动时)创建 IOC 容器。
1. ServletContextListener 接口 ServletContextListener 包含两个核心方法,分别在 Web 应用启动和关闭时触发:
1 2 3 4 5 6 7 public interface ServletContextListener extends EventListener { void contextInitialized (ServletContextEvent sce) ; void contextDestroyed (ServletContextEvent sce) ; }
ServletContextEvent:事件对象,可通过 getServletContext() 方法获取 ServletContext 实例;
ServletContext:Web 应用的全局上下文,整个应用共享一个实例,可用于存储全局数据(如 Spring 容器)。
2. Spring 提供的监听器:ContextLoaderListener Spring 框架提供了 ContextLoaderListener 类,它实现了 ServletContextListener 接口,是 Web 应用中初始化 Spring 容器的核心类。其工作流程如下:
Web 应用启动 :Servlet 容器调用 ContextLoaderListener.contextInitialized() 方法;
创建 Spring 容器 :ContextLoaderListener 读取配置文件(如 applicationContext.xml),初始化 WebApplicationContext(Spring 专为 Web 环境设计的 IOC 容器);
存储容器到 ServletContext :将 WebApplicationContext 实例存入 ServletContext,键为固定值 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
Web 应用关闭 :调用 contextDestroyed() 方法,销毁 Spring 容器,释放资源。
ContextLoaderListener 的核心逻辑(简化):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ContextLoaderListener extends ContextLoader implements ServletContextListener { @Override public void contextInitialized (ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } @Override public void contextDestroyed (ServletContextEvent event) { closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }
Web 应用整合 Spring 的配置步骤 1. 引入依赖(Maven) 需引入 Spring Web 模块(包含 ContextLoaderListener 等类)和 Servlet API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-web</artifactId > <version > 4.3.29.RELEASE</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > javax.servlet-api</artifactId > <version > 3.1.0</version > <scope > provided</scope > </dependency >
2. 配置 Spring 监听器和配置文件路径 在 web.xml 中配置 ContextLoaderListener 并指定 Spring 配置文件的位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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_3_1.xsd" version ="3.1" > <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 > </web-app >
默认配置文件路径 :若不配置 contextConfigLocation,Spring 会默认加载 /WEB-INF/applicationContext.xml;
多配置文件 :可通过逗号分隔多个配置文件,如 classpath:spring-dao.xml,classpath:spring-service.xml。
3. 创建 Spring 配置文件(applicationContext.xml) 在 src/main/resources 下创建 Spring 核心配置文件,定义 Bean 和组件扫描:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?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.web" /> </beans >
4. 在 Web 组件中获取 Spring 容器 初始化后,Spring 容器存储在 ServletContext 中,可在 Servlet、Filter 等 Web 组件中通过 WebApplicationContextUtils 工具类获取:
示例:在 Servlet 中获取 Spring 容器并使用 Bean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/user") public class UserServlet extends HttpServlet { private UserService userService; @Override public void init () throws ServletException { ServletContext servletContext = getServletContext(); WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext); userService = context.getBean(UserService.class); } @Override protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws IOException { String username = userService.getUsernameById(1L ); resp.getWriter().write("Username: " + username); } }
示例:Service 层 Bean(被 Spring 管理) 1 2 3 4 5 6 7 8 9 import org.springframework.stereotype.Service;@Service public class UserService { public String getUsernameById (Long id) { return "张三" ; } }
Spring Web 容器的特殊之处:WebApplicationContext 在 Web 应用中,Spring 容器的类型是 WebApplicationContext,它是 ApplicationContext 的子接口,专为 Web 环境扩展了以下功能:
关联 ServletContext :通过 getServletContext() 方法直接获取 ServletContext;
支持主题(Theme) :管理 Web 应用的主题资源(如 CSS、图片);
分层容器:在 Spring MVC 中,WebApplicationContext可分为根容器(由ContextLoaderListener创建)和Servlet 容器(由DispatcherServlet创建),实现职责分离:
根容器:管理 Service、Dao 等全局 Bean;
Servlet 容器:管理 Controller、ViewResolver 等 MVC 相关 Bean,且可引用根容器的 Bean。
无 web.xml 配置(Servlet 3.0+ 注解驱动) Servlet 3.0 及以上支持完全注解驱动的配置,无需 web.xml,通过 WebApplicationInitializer 接口实现 Spring 容器的初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import org.springframework.web.WebApplicationInitializer;import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import org.springframework.web.servlet.DispatcherServlet;import javax.servlet.ServletContext;import javax.servlet.ServletRegistration;public class MyWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup (ServletContext servletContext) { AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(RootConfig.class); // 注册根配置类 servletContext.addListener(new ContextLoaderListener(rootContext)); AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext(); mvcContext.register(MvcConfig.class); // 注册 MVC 配置类 ServletRegistration.Dynamic dispatcher = servletContext.addServlet( "dispatcher" , new DispatcherServlet(mvcContext) ); dispatcher.setLoadOnStartup(1 ); dispatcher.addMapping("/" ); } } import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration @ComponentScan(basePackages = {"com.example.service", "com.example.dao"}) public class RootConfig {} @Configuration @ComponentScan(basePackages = "com.example.controller") public class MvcConfig {}
原理 :Servlet 3.0+ 容器启动时,会扫描类路径下所有实现 WebApplicationInitializer 的类,并调用其 onStartup() 方法,从而实现无 XML 配置。
总结 Spring 与 Web 应用的整合核心是通过 ContextLoaderListener 监听器,在 Servlet 容器启动时初始化 WebApplicationContext,并将其存储在 ServletContext 中,供整个 Web 应用共享。关键步骤包括:
配置 ContextLoaderListener 监听器(web.xml 或注解方式);
指定 Spring 配置文件路径(contextConfigLocation 参数);
通过 WebApplicationContextUtils 在 Web 组件中获取 Spring 容器及 Bean
v1.3.10