Spring MVC 上下文(ApplicationContext)初始化入口
Spring 常用上下文容器有哪些
ApplicationContext
ClassPathXmlApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
AnnotationConfigApplicationContext
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
应该来说是很少使用这种方法用于生产开发,常常在学习Spring做demo的时候会使用到。更有可能出现在Spring项目的代码测试,不过呢,单元测试的框架(比如 JUnit)已经提供了简单的方式,也就不建议直接实例化上下文。因为实例化一个上下文还得要做维护,再者现在常用的是基于Web的开发,也就是常用 Spring MVC。如果没有基于 Web 应用的开发,那么很可能就是一个小的程序,类似于提供给第三方使用的 SDK 代码,那么使用 Spring 感觉会太重,最重要是自己要维护一个 ApplicationContext,感觉不是那么方便
Web ApplicationContext
以下两个是针对 Spring MVC 的应用上下文。WebApplicationContext 实例会在应用启动之后由Spring实例化并维护,而平常在学习的时候也往往不会自己去实例化 WebApplicationContext 对象,因为将因为部署到web容器(比如 tomcat),启动之后就可以直接测试了。单元测试有专门的框架处理(比如 JUnit),可以很简单的实现测试。web项目的开发关键点在于让web容器初始化之后提醒Spring ApplicationContext 初始化,例如 tomcat 的 ServletContext 会维护一个 WebApplicationContext。
XmlWebApplicationContext
@Test
public void handlerBeanNotFound() throws Exception {
MockServletContext sc = new MockServletContext("");
XmlWebApplicationContext root = new XmlWebApplicationContext();
root.setServletContext(sc);
root.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map1.xml"});
root.refresh();
XmlWebApplicationContext wac = new XmlWebApplicationContext();
wac.setParent(root);
wac.setServletContext(sc);
wac.setNamespace("map2err");
wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2err.xml"});
try {
wac.refresh();
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (FatalBeanException ex) {
NoSuchBeanDefinitionException nestedEx = (NoSuchBeanDefinitionException) ex.getCause();
assertEquals("mainControlle", nestedEx.getBeanName());
}
}
AnnotationConfigWebApplicationContext:没找到合适的示例代码
ApplicationContext 入口
这种方式需要自己维护 ApplicationContext 实例,也就是开发使用的时候 new ApplicationContext
,入口自己控制
WebApplicationContext 入口
web.xml 配置和 全注解 配置启动会有一些差别。
web.xml 配置
web.xml 中关于Spring的配置项,也非常常见。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- 上下文参数,在监听器中被使用,实际就是key-value,key=contextConfigLocation 写死 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<!-- 监听器配置,初始化 WebApplicationContext -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 前端控制器配置 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
WebApplicationContext 的初始化调用链路:ContextLoaderListener.contextInitialized-->ContextLoader.initWebApplicationContext-->ContextLoader.createWebApplicationContext-->ContextLoader.determineContextClass-->ContextLoader.determineContextClass。
determineContextClass 源码如下:
protected Class<?> determineContextClass(ServletContext servletContext) {
// 自定义的 ApplicationContext
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
// 缺省为 XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
默认 WebApplicationContext
根据上面的 web.xml 配置是没有指定 ApplicationContext 的实现的,所以会执行:contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
。defaultStrategies 的实现如下:
/**
* Name of the class path resource (relative to the ContextLoader class)
* that defines ContextLoader's default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
private static final Properties defaultStrategies;
static {
// 读取文件 ContextLoader.properties 中的配置
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
根据 ContextLoader.properties 中的配置完成,里边的内容如下:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
所以呢,通过 web.xml 配置Spring MVC默认的上下文是: XmlWebApplicationContext
指定 WebApplicationContext
如果在 web.xml 中配置 contextClass 属性,例如下面的方式,摘自 StackOverflow:How to register Spring @Configuration annotated class instead of applicationContext.xml file in web.xml?
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
感觉很神奇,但是也很麻烦的样子。我是不建议混合 web.xml 配置启动和全注解启动,乱且不好看懂。
全注解配置
全注解方式一般是实现WebApplicationInitializer
或者通过继承AbstractAnnotationConfigDispatcherServletInitializer
。AbstractAnnotationConfigDispatcherServletInitializer
是WebApplicationInitializer
的实现类。想知道全注解配置下tomcat如何Spring IOC怎样被加载,可以阅读篇文章Spring揭秘--寻找遗失的web.xml
全注解方式配置常用类似如下的代码:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* @author imssbora
*/
public class MyWebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer{
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
启动路径:SpringServletContainerInitializer.onStartup-->AbstractContextLoaderInitializer.onStartup-->AbstractContextLoaderInitializer.registerContextLoaderListener-->AbstractAnnotationConfigDispatcherServletInitializer.createRootApplicationContext。
createRootApplicationContext 源码如下:
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = this.getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
} else {
return null;
}
}
可以看出实例化了 AnnotationConfigWebApplicationContext
对象。
参考
关于web.xml配置启动,Spring 的加载流程网络上资料很多,所以有可能会有很多重复的,选择一遍排版不错,写得相对完整的,编写时间比较新的:Spring MVC 启动过程源码分析。
排版精美,写得很棒的文章:Spring揭秘--寻找遗失的web.xml
从 StackOverflow 上找到的资料:How to register Spring @Configuration annotated class instead of applicationContext.xml file in web.xml?
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=38db6z9qc328s
时间:2018.9.3 16:20
Spring MVC 上下文(ApplicationContext)初始化入口的更多相关文章
- 死磕Spring之IoC篇 - Spring 应用上下文 ApplicationContext
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- Spring MVC之DispatcherServlet初始化详解
Spring作为一个优秀的web框架,其运行是基于Tomcat的.在我们前面的讲解中,Spring的驱动都是使用的ClassPathXmlApplicationContext,并且都是直接在main方 ...
- Spring MVC之RequestMappingHandlerAdapter初始化
RequestMappingHandlerAdapter基于注解的处理器适配器,目的是用来执行handler,同时返回modelAndView给前端控制器,这块个人感觉是spring mvc的核心了, ...
- spring mvc之applicationContext
1.ApplicationContext是在package org.springframework.context下,是spring的,spring context包下的. applicationCo ...
- spring mvc 下 applicationContext 和webApplicationContext
spring中的ApplicationContexts可以被限制在不同的作用域.在web框架中,每个DispatcherServlet有它自己的WebApplicationContext,它包含了Di ...
- Spring MVC启动时初始化的几个常用方法
Spring-MVC的应用中,要实现类似的功能,主要是通过实现下面这些接口(任选一,至少一个即可) 一.ApplicationContextAware接口 +? 1 2 3 4 5 6 7 8 9 p ...
- 【Spring学习笔记-3.1】让bean获取spring容器上下文(applicationContext.xml)
*.hl_mark_KMSmartTagPinkImg{background-color:#ffaaff;}*.hl_mark_KMSmartTagBlueImg{background-color:# ...
- spring MVC模式拦截所有入口方法的入参出参打印
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; im ...
- Spring MVC(一)--SpringMVC的初始化和流程
SpringMVC是Spring提供给WEB应用的MVC框架,MVC框架一般来说由三部分组成: Model:模型层,一般由java bean完成,主要是进行数据库操作: View:视图层,用于前端展示 ...
随机推荐
- Centos 7 squid 用户认证
一.安装安装过程十分简便,只需要安装一下squid,一条命令搞定yum install squidrpm -qa | grep squidsquid-3.5.20-2.el7_3.2.x86_64 二 ...
- linux常用命令 sort排序命令
排序命令sort sort [选项] 文件名 选项 -f 忽略大小写 -n 以数值型进行排序,默认使用字符串型进行排序 -r 反向排序 -t 指定分割符,默认的分割符是制表符 -k n[,m] 安装自 ...
- freemarker导出word档
1.word另存为xml:2.xml文件后缀名改成ftl:3.编写完整json字符串备用:4.修改ftl中动态字段为json中对应字段名:5.编写java代码自动生成word文件:(注意:换行用< ...
- javascript事件流机制
(1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div ...
- Kali Linux搭建Go语言环境
准备: (1)Kali Linux系统(此实验为VMware环境) (2)Go语言安装包 具体过程: (1)到官网下载Go语言安装包,如图示操作(官网可能需要梯子,没有的可以从国内相关网站下载) ( ...
- Django部署以及整合celery
前言 Djngo部署的结构一般都是nginx+uwsgi+python web 一.新建一个Djang项目并合并celery 项目名随便打的..命名规范驼峰啥的别和我扯犊子哈 跑一下,然后我们就有一个 ...
- Linux SSH登录服务器报ECDSA host key "ip地址" for has changed and you have requested strict checking错误
错误:ECDSA host key "ip地址" for has changed and you have requested strict checking. 解决方案:在终端 ...
- tensorflow (七) k-means
tensorflow基础暂不介绍 Python 相关库的安装 在进入正式聚类实验之前,我们还需要配置计算及画图需要用到相关支持包. 安装 seaborn: pip install seaborn 安装 ...
- 五、docker网络技术
五 docker网络技术 1.本章环境: 源码文件目录: 2.网络基础回顾 通道: NAT将私有地址和端口号翻译成公有的地址和端口号项某网站发出数据包.某网站根据数据表查出私有ip和端口号返回数据. ...
- 安装selenium,驱动geckodriver,及出现的问题
cmd输入安装selenium指令: pip install selenium 1.报错 Could not find a version that satisfies the requirement ...