SpringBoot和SpringMvc中的Context
字数 1551 2025-08-26 22:11:45
SpringBoot和SpringMVC中的Context详解
前言
在学习内存马技术时,经常会遇到Spring框架中的ChildContext和RootContext概念,这些概念对于理解Spring的上下文机制至关重要。本文将详细解析Spring MVC和Spring Boot中的上下文结构差异。
基本概念
ContextLoaderListener和DispatcherServlet
在传统Spring MVC应用中,通常使用两个关键组件来加载不同的Spring配置文件:
- ContextLoaderListener:加载applicationContext.xml,对应Root WebApplicationContext
- DispatcherServlet:加载servlet-context.xml,对应Child WebApplicationContext
父子上下文关系
- RootContext:由ContextLoaderListener创建,是整个应用的父上下文
- ChildContext:由DispatcherServlet创建,是子上下文,可以有多个
- 两者是继承关系,ChildContext可以通过
getParent()方法获取到RootContext
Spring MVC中的上下文机制
上下文获取方式
- 获取RootContext:
WebApplicationContext root = ContextLoader.getCurrentWebApplicationContext();
- 通过ServletContext获取RootContext:
ServletContext servletContext = root.getServletContext();
WebApplicationContext root = (WebApplicationContext)servletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
- 获取ChildContext:
WebApplicationContext child = (WebApplicationContext)request.getAttribute(
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
上下文特性验证
// 验证RootContext和ChildContext的关系
System.out.println("is parent==" + (child.getParent() == root));
// 检查Bean存在性
System.out.println("root:" + root.containsLocalBean("myService")); // false
System.out.println("child:" + child.containsLocalBean("myService")); // true
关键发现
- RootContext无法访问ChildContext中的Bean
- ChildContext可以访问RootContext中的Bean
- Bean名称存储时首字母会转为小写
Spring Boot中的上下文机制
与Spring MVC的主要区别
- 单一上下文:Spring Boot中只有一个RootContext,没有ChildContext
- 所有Bean都注册在这个单一的上下文中
- 获取方式不同:
// 获取Spring Boot的RootContext
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(
RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())
.getRequest()).getServletContext());
上下文类型
Spring Boot中使用的是AnnotationConfigServletWebApplicationContext,其parent为null,表明它是RootContext。
配置文件的对应关系
Spring MVC典型配置
- RootContext配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- ChildContext配置:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcherServlet.xml</param-value>
</init-param>
</servlet>
Bean扫描规则
在哪个配置文件中声明注解扫描标签,扫描到的Bean就会被注册到对应的上下文中:
<context:component-scan base-package="Controller"/>
总结对比
相同点
- ServletContext都是
ApplicationContextFacade对象 - 作用范围都是ServletContext最大,其他Context都是它的属性
不同点
| 特性 | Spring MVC | Spring Boot |
|---|---|---|
| 上下文数量 | 多个(1个Root + n个Child) | 单一RootContext |
| Bean存储 | 分散在不同上下文中 | 全部存储在单一上下文中 |
| 获取方式 | 有多种获取特定上下文的方法 | 统一获取方式 |
实际应用意义
- 内存马注入:通常选择获取ChildContext而非RootContext,因为ChildContext可以访问更多资源
- Bean查找:需要注意Bean名称的首字母小写规则
- 上下文隔离:理解父子上下文关系有助于设计合理的应用结构
参考资源
通过深入理解Spring的上下文机制,开发者可以更好地掌握框架的核心原理,为高级应用和问题排查打下坚实基础。