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的配置项,也非常常见。
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">
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
dispatcher
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:applicationContext-mvc.xml
1
dispatcher
/
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?
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.acme.AppConfig
org.springframework.web.context.ContextLoaderListener
dispatcher
org.springframework.web.servlet.DispatcherServlet
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.acme.web.MvcConfig
dispatcher
/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 对象。
加Java架构师进阶交流群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限 都是大牛带飞 让你少走很多的弯路的 群.号是 338549832 对了 小白勿进 最好是有开发经验
注:加群要求
1、具有工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。
2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。
3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。
4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。
5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!
閱讀更多 java開發者 的文章