`
dxm1986
  • 浏览: 429792 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Web开发中获取Spring的ApplicationContext的三种方式

阅读更多

前两天在写这编文章的时候出了N次错,今天还是决定重新把它简单的记录一下。

 

在 WEB 开发中,可能会很少需要显示的获得 ApplicationContext 来得到由 Spring 进行管理的某些 Bean, 今天我就遇到了,在这里和大家分享一下, WEB 开发中,怎么获取 ApplicationContext

一       要想怎么获取 ApplicationContext, 首先必须明白 Spring 内部 ApplicationContext 是怎样存储的。下面我们来跟踪一下源码

首先:从大家最熟悉的地方开始 

<listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

 上面这一段,大家很熟悉吧。好,让我们看一看它到底实现了些啥。

 

 

public class ContextLoaderListener implements ServletContextListener {

	private ContextLoader contextLoader;

	/**
	 * Initialize the root web application context.
	 */
	public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}//下面的略

 
显然,ContextLoaderListener实现了ServeletContextListenet,在ServletContext初始化的时候,会进行Spring的初始化,大家肯定会想,Spring的初始化应该与ServletContext有一定关系吧?有关系吗?接下来让我们进入

ContextLoader.initWebApplicationContext方法

 

 

public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
			throws IllegalStateException, BeansException {

		//从ServletContext中查找,是否存在以WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为Key的值
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

				
		try {
			// Determine parent for root web application context, if any.
			ApplicationContext parent = loadParentContext(servletContext);

			// it is available on ServletContext shutdown.
			this.context = createWebApplicationContext(servletContext, parent);
			//将ApplicationContext放入ServletContext中,其key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
			//将ApplicationContext放入ContextLoader的全局静态常量Map中,其中key为:Thread.currentThread().getContextClassLoader()即当前线程类加载器
			currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);

			return this.context;
		}
	}

 从上面的代码大家应该明白了Spring初始化之后,将ApplicationContext存到在了两个地方,那么是不是意味着我们可以通过两种方式取得ApplicationContext?

 

第一种获取方式:


 注意:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

即为 "org.springframework.web.context.WebApplicationContext.ROOT"

 

那么咱们是不是可以这样获得ApplicationContext:

  

request.getSession().getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT")

 确实可以,而且我们想到这种方法的时候,Spring早就提供给我们接口了:

 

public abstract class WebApplicationContextUtils {
	
		 
public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
	    throws IllegalStateException {

		WebApplicationContext wac = getWebApplicationContext(sc);
		if (wac == null) {
			throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
		}
		return wac;
	}

 getWebApplicationContext方法如下:

 

 

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
		return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	}

 哈哈,明白了吧,它和我们自己实现的方法是一样的。

 

现在看一下第二种方法:

 

前面说到Spring初始化的时候,将ApplicationContext还存了一份到ContextLoader的Map里面,那么我们是不是可以通过Map.get(key)  ???很不幸的是,这个Map是私有的。LOOK:

 

private static final Map currentContextPerThread = CollectionFactory.createConcurrentMapIfPossible(1);

 

不过,不用担心Spring为我们提供了方法:再LOOK:

 

public static WebApplicationContext getCurrentWebApplicationContext() {
		return (WebApplicationContext) currentContextPerThread.get(Thread.currentThread().getContextClassLoader());
	}

 

这下我们放心了吧!哈哈,第二种方法也搞定了。第二种方法与第一种方法相比有什么好的地方呢?就是它不需要参数,只要在Web容器中,当Spring初始化之后,你不需要传入任何参数,就可以获得ApplicationContext为咱们服务。是不是很好?不过作者在用这个方法的时候,发现在Spring2.52版本中是不存在的,但是在2.5.5版本中提供了!!

 

其实第二种获取方法看上去简单,但他的原理还是有一定难度的,他与类加载器的线程上下文相关,有不知道大家有没有听说过,这个线程上下文在咱们常用的Mysql驱动中有用到,下次可以和大家一起分享一下。

 

第三种方式:借用ApplicationContextAware,ApplicationContext的帮助类能够自动装载ApplicationContext,只要你将某个类实现这个接口,并将这个实现类在Spring配置文件中进行配置,Spring会自动帮你进行注

入 ApplicationContext.ApplicationContextAware的代码结构如下:

 

 

public interface ApplicationContextAware {
	
		void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

 

就这一个接口。可以这样简单的实现一个ApplicationContextHelper类:

 

 

 

 

public class ApplicationHelper implements ApplicationContextAware {

	
	private ApplicationContext applicationContext;
	
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
			this.applicationContext = applicationContext;
	}

	
	public  ApplicationContext getApplicationContext(){
		return this.applicationContext;
	}
}

 

通过ApplicationHelper我们就可以获得咱们想要的AppilcationContext类了

 

 

7
2
分享到:
评论
5 楼 雪之痕 2012-12-06  
嗯,楼主写的不错,受教了!
4 楼 dxm1986 2010-09-20  
PS:
org.springframework.web.servlet.FrameworkServlet.CONTEXT.dis 其中dis为DispatcherServlet在web.xml中的配置名字。

String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);

public String getServletContextAttributeName() {
    return SERVLET_CONTEXT_PREFIX + getServletName();
}

public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";

public final String getServletName() {
return (getServletConfig() != null ? getServletConfig().getServletName() : null);
}
3 楼 dxm1986 2010-09-20  
zywang 写道
你找找用Struts集成Spring的时候wac被保存到什么地方去的吧,貌似不是org.springframework.web.context.WebApplicationContext.ROOT这个地址,我讲的是spring2.5.5版本的

我试了是可以的。

ApplicationContext application = (ApplicationContext)req.getSession().getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT");

这样我取得了我想要的ApplicationContext

我不知你初始化Spring是用的哪个,如果用org.springframework.web.servlet.DispatcherServlet进行初始化,在DispatcherServlet extends FrameworkServlet
FrameworkServlet.initWebApplicationContext()方法中有
getServletContext().setAttribute(attrName, wac);

debug时发现attrName="org.springframework.web.servlet.FrameworkServlet.CONTEXT.dis" 不知道你是不是说的这种情况。
2 楼 zywang 2010-09-20  
你找找用Struts集成Spring的时候wac被保存到什么地方去的吧,貌似不是org.springframework.web.context.WebApplicationContext.ROOT这个地址,我讲的是spring2.5.5版本的
1 楼 dxm1986 2010-09-19  
我晕,某些标红的地方,又变成<SPAN style="COLOR: #ff0000">****</SPAN>了,javaeye的编辑器有问题呀。

相关推荐

    Spring.3.x企业应用开发实战(完整版).part2

    1.7 如何获取Spring 1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 ...

    Spring 2.0 开发参考手册

    3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.9.1. 使用Singleton-helper类 4. 资源 4.1. 简介 4.2. Resource 接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. ...

    Java后端开发-Spring库.zip

    4.测试:启动Spring,获取Hello示例。 二、Spring基于XML装配实验 说明:使用Spring IOC模拟实现账户添加功能程序 1.创建JavaBean类:Account.java 2.创建DAO类: AccountDao.java,模拟账户添加操作 3.创建Service...

    Spring3.x企业应用开发实战(完整版) part1

    1.7 如何获取Spring 1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 ...

    Spring中文帮助文档

    3.8.5. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.10. 以J2EE RAR文件的形式部署Spring ApplicationContext 3.11. 基于注解(Annotation-based)的配置 3.11.1. @Autowired ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.9.1. 使用Singleton-helper类 4. 资源 4.1. 简介 4.2. Resource 接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. Class...

    ssh(structs,spring,hibernate)框架中的上传下载

    WEB-INF下的applicationContext.xml为Spring的配置文件,struts-config.xml为Struts的配置文件,file-upload.jsp为文件上传页面,file-list.jsp为文件列表页面。  本文后面的章节将从数据持久层->业务层->Web层的...

    Spring API

    3.8.5. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.10. 以J2EE RAR文件的形式部署Spring ApplicationContext 3.11. 基于注解(Annotation-based)的配置 3.11.1. @Autowired ...

    spring chm文档

    3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.9.1. 使用Singleton-helper类 4. 资源 4.1. 简介 4.2. Resource 接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. ...

    java命名规范 开发规范

    Spring管理第三方WebService实例bean Jaxws-client配置代码 b. 生成第三方WebService接口文件;(提供系统自动生成) 自动生成代码 c. 页面调用Action请求,Action中注入WebService实例bean; Action对应方法直接...

    springmybatis

    1. 现阶段,你可以直接建立java 工程,但一般都是开发web项目,这个系列教程最后也是web的,所以一开始就建立web工程。 2. 将 mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar 拷贝到 web工程的...

    J2EE应用开发详解

    17 2.1.1 安装JDK 17 2.1.2 安装Tomcat 21 2.1.3 安装Eclipse 23 2.2 配置开发环境 23 2.3 小结 26 第3章 Java的反射机制 27 3.1 Java反射API 27 3.2 加载类的实例 29 3.2.1 加载class对象的两种方式 29 3.2.2 Class...

    java面试宝典

    22、我们在web 应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 10 23、String 和StringBuffer 的区别? 10 24、String, StringBuffer StringBuilder 的区别。 10 25、...

    java微信公众号MVC开发框架

    web.xml是web应用的配置文件,jwx从spring配置文件中获取配置信息,所以必须配置spring上下文环境;另外,需要配置微信消息处理分发Servlet(WeixinDispatcherServlet),用于处理微信送过来的请求消息或事件。jwx对...

    springboot参考指南

    开发你的第一个Spring Boot应用 v. 11.1. 创建POM vi. 11.2. 添加classpath依赖 vii. 11.3. 编写代码 i. 11.3.1. @RestController和@RequestMapping注解 ii. 11.3.2. @EnableAutoConfiguration注解 iii. 11.3.3. ...

    客户关系管理系统框架搭建(二)

    * junit:开发人员测试用的 * 搭建hibernate层 * 定义需求:部门信息的页面数据要插入到数据库中 * 定义表 CREATE TABLE `sys_user_group` ( `id` INTEGER(11) NOT NULL AUTO_INCREMENT, #编号 ...

    千方百计笔试题大全

    22、我们在web 应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 10 23、String 和StringBuffer 的区别? 10 24、String, StringBuffer StringBuilder 的区别。 10 25、...

    将 Flex 集成到 Java EE 应用程序的最佳实践(完整源代码)

    对这个简单的应用,省略了 DAO,直接在 Façade 中通过 Spring 的 JdbcTemplate 操作数据库。最后,EmployeeMgmt 应用通过 Servlet 和 JSP 页面为用户提供前端界面: 图 2. EmployeeMgmt Web 界面 该界面为传统...

    +Flex+集成到+Java+EE+应用程序的最佳实践(完整源代码)

    因此,需要一个 FactoryInstance 的实现类,我们编写一个 SpringFactoryInstance,以便从 Spring 的容器中查找 FlexService: 清单 9. SpringFactoryInstance class class SpringFactoryInstance extends ...

Global site tag (gtag.js) - Google Analytics