<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>I@laoer.com &#187; Spring</title>
	<atom:link href="http://i.laoer.com/tag/spring/feed" rel="self" type="application/rss+xml" />
	<link>http://i.laoer.com</link>
	<description>技术、生活、感悟 -- Laoer的博客</description>
	<lastBuildDate>Mon, 15 Feb 2010 08:36:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ApplicationContext研究</title>
		<link>http://i.laoer.com/spring-applicationcontext.html</link>
		<comments>http://i.laoer.com/spring-applicationcontext.html#comments</comments>
		<pubDate>Tue, 10 Feb 2009 07:08:19 +0000</pubDate>
		<dc:creator>Laoer</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring]]></category>

		<guid isPermaLink="false">http://i.laoer.com/?p=14</guid>
		<description><![CDATA[ApplicationContext是Spring的核心，Context我们通常解释为上下文环境，我想用“容器”来表述它更容易理解一些，ApplicationContext则是“应用的容器”了:P，Spring把Bean放在这个容器中，在需要的时候，用getBean方法取出，虽然我没有看过这一部分的源代码，但我想它应该是一个类似Map的结构。
在Web应用中，我们会用到WebApplicationContext，WebApplicationContext继承自ApplicationContext，先让我们看看在Web应用中，怎么初始化WebApplicationContext，在web.xml中定义:
&#60;context-param&#62;
&#60;param-name&#62;contextConfigLocation&#60;/param-name&#62;
&#60;param-value&#62;/WEB-INF/applicationContext.xml&#60;/param-value&#62;
&#60;/context-param&#62;
&#60;listener&#62;
&#60;listener-class&#62;org.springframework.web.context.ContextLoaderListener&#60;/listener-class&#62;
&#60;/listener&#62;
&#60;!&#8211; OR USE THE CONTEXTLOADERSERVLET INSTEAD OF THE  LISTENER
&#60;servlet&#62;
&#60;servlet-name&#62;context&#60;/servlet-name&#62;
&#60;servlet-class&#62;org.springframework.web.context.ContextLoaderServlet&#60;/servlet-class&#62;
&#60;load-on-startup&#62;1&#60;/load-on-startup&#62;
&#60;/servlet&#62;
&#8211;&#62;
可以看出，有两种方法，一个是用ContextLoaderListener这个Listerner，另一个是ContextLoaderServlet这个Servlet，这两个方法都是在web应用启动的时候来初始化WebApplicationContext，我个人认为Listerner要比Servlet更好一些，因为Listerner监听应用的启动和结束，而Servlet得启动要稍微延迟一些，如果在这时要做一些业务的操作，启动的前后顺序是有影响的。
那么在ContextLoaderListener和ContextLoaderServlet中到底做了什么呢？
以ContextLoaderListener为例，我们可以看到
public  void contextInitialized(ServletContextEvent event) {
this.contextLoader =  createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
protected  ContextLoader createContextLoader() {
return new  ContextLoader();
}
ContextLoader是一个工具类，用来初始化WebApplicationContext，其主要方法就是initWebApplicationContext，我们继续追踪initWebApplicationContext这个方法（具体代码我不贴出，大家可以看Spring中的源码），我们发现，原来ContextLoader是把WebApplicationContext（XmlWebApplicationContext是默认实现类）放在了ServletContext中，ServletContext也是一个“容器”，也是一个类似Map的结构，而WebApplicationContext在ServletContext中的KEY就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE，我们如果要使用WebApplicationContext则需要从ServletContext取出，Spring提供了一个WebApplicationContextUtils类，可以方便的取出WebApplicationContext，只要把ServletContext传入就可以了。
上面我们介绍了WebApplicationContext在Servlet容器中初始化的原理，一般的Web应用就可以轻松的使用了，但是，随着Struts的广泛应用，把Struts和Spring整个起来，是一个需要面对的问题，Spring本身也提供了Struts的相关类，主要使用的有org.springframework.web.struts.ActionSupport，我们只要把自己的Action继承自ActionSupport，就是可以调用ActionSupport中getWebApplicationContext()的方法取出WebApplicationContext，但这样一来在Action中，需要取得业务逻辑的地方都要getBean，看上去不够简洁，所以Spring又提供了另一个方法，用org.springframework.web.struts.ContextLoaderPlugIn，这是一个Struts的Plug，在Struts启动时加载，对于Action，可以像管理Bean一样来管理，在struts-config.xml中Action的配置变成类似下面的样子
&#60;action  attribute=&#8221;aForm&#8221; name=&#8221;aForm&#8221; path=&#8221;/aAction&#8221;  scope=&#8221;request&#8221;  type=&#8221;org.springframework.web.struts.DelegatingActionProxy&#8221;&#62;
&#60;forward name=&#8221;forward&#8221; path=&#8221;forward.jsp&#8221;  /&#62;
&#60;/action&#62;
注意type变成了org.springframework.web.struts.DelegatingActionProxy，之后我们需要建立action-servlet.xml这样的文件，action-servlet.xml符合Spring的spring-beans.dtd标准，在里面定义类似下面的
&#60;bean  name=&#8221;/aAction&#8221; class=&#8221;com.web.action.Aaction&#8221; singleton=&#8221;false&#8221;&#62;
&#60;property name=&#8221;businessService&#8221;&#62;
&#60;ref  bean=&#8221;businessService&#8221;/&#62;
&#60;/property&#62;
&#60;/bean&#62;
com.web.action.Aaction是Action的实现类，businessService是需要的业务逻辑，Spring会把businessService注入到Action中，在Action中只要写businessService的get和set方法就可以了，还有一点，action的bean是singleton=&#8221;false&#8221;，即每次新建一个实例，这也解决了Struts中Action的线程同步问题，具体过程是当用户做“/aAction”的HTTP请求（当然应该是“/aAction.do”），Struts会找到这个Action的对应类org.springframework.web.struts.DelegatingActionProxy，DelegatingActionProxy是个代理类，它会去找action-servlet.xml文件中“/aAction”对应的真正实现类，然后把它实例化，同时把需要的业务对象注入，然后执行Action的execute方法。
使用了ContextLoaderPlugIn，在struts-config.xml中变成类似这样配置
&#60;plug-in  className=&#8221;org.springframework.web.struts.ContextLoaderPlugIn&#8221;&#62;
&#60;set-property property=&#8221;contextConfigLocation&#8221;  value=&#8221;/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml&#8221;  /&#62;
&#60;/plug-in&#62;
而在web.xml中不再需要ContextLoaderListener或是ContextLoaderServlet。
说到这里不知道大家会不会有这样的问题，如果使用ContextLoaderPlugIn，如果我们有些程序是脱离Struts的Action环境，我们怎么处理，比如我们要自定义标记库，在标记库中，我们需要调用Spring管理的业务层逻辑对象，这时候我们就很麻烦，因为只有在action中动态注入业务逻辑，其他我们似乎不能取得Spring的WebApplicationContext。
别急，我们还是来看一下ContextLoaderPlugIn的源码（源码不再贴出），我们可以发现，原来ContextLoaderPlugIn仍然是把WebApplicationContext放在ServletContext中，只是这个KEY不太一样了，这个KEY值为ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX+ModuleConfig.getPrefix()（具体请查看源代码），这下好了，我们知道了WebApplicationContext放在哪里，只要我们在Web应用中能够取到ServletContext也就能取到WebApplicationContext了:)
]]></description>
			<content:encoded><![CDATA[<p>ApplicationContext是Spring的核心，Context我们通常解释为上下文环境，我想用“容器”来表述它更容易理解一些，ApplicationContext则是“应用的容器”了:P，Spring把Bean放在这个容器中，在需要的时候，用getBean方法取出，虽然我没有看过这一部分的源代码，但我想它应该是一个类似Map的结构。<br />
在Web应用中，我们会用到WebApplicationContext，WebApplicationContext继承自ApplicationContext，先让我们看看在Web应用中，怎么初始化WebApplicationContext，在web.xml中定义:<br />
&lt;context-param&gt;<br />
&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br />
&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;<br />
&lt;/context-param&gt;</p>
<p>&lt;listener&gt;<br />
&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;<br />
&lt;/listener&gt;</p>
<p>&lt;!&#8211; OR USE THE CONTEXTLOADERSERVLET INSTEAD OF THE  LISTENER<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;context&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;org.springframework.web.context.ContextLoaderServlet&lt;/servlet-class&gt;<br />
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
&lt;/servlet&gt;<br />
&#8211;&gt;</p>
<p>可以看出，有两种方法，一个是用ContextLoaderListener这个Listerner，另一个是ContextLoaderServlet这个Servlet，这两个方法都是在web应用启动的时候来初始化WebApplicationContext，我个人认为Listerner要比Servlet更好一些，因为Listerner监听应用的启动和结束，而Servlet得启动要稍微延迟一些，如果在这时要做一些业务的操作，启动的前后顺序是有影响的。</p>
<p>那么在ContextLoaderListener和ContextLoaderServlet中到底做了什么呢？<br />
以ContextLoaderListener为例，我们可以看到<br />
public  void contextInitialized(ServletContextEvent event) {<br />
this.contextLoader =  createContextLoader();<br />
this.contextLoader.initWebApplicationContext(event.getServletContext());<br />
}<br />
protected  ContextLoader createContextLoader() {<br />
return new  ContextLoader();<br />
}<br />
ContextLoader是一个工具类，用来初始化WebApplicationContext，其主要方法就是initWebApplicationContext，我们继续追踪initWebApplicationContext这个方法（具体代码我不贴出，大家可以看Spring中的源码），我们发现，原来ContextLoader是把WebApplicationContext（XmlWebApplicationContext是默认实现类）放在了ServletContext中，ServletContext也是一个“容器”，也是一个类似Map的结构，而WebApplicationContext在ServletContext中的KEY就是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE，我们如果要使用WebApplicationContext则需要从ServletContext取出，Spring提供了一个WebApplicationContextUtils类，可以方便的取出WebApplicationContext，只要把ServletContext传入就可以了。</p>
<p>上面我们介绍了WebApplicationContext在Servlet容器中初始化的原理，一般的Web应用就可以轻松的使用了，但是，随着Struts的广泛应用，把Struts和Spring整个起来，是一个需要面对的问题，Spring本身也提供了Struts的相关类，主要使用的有org.springframework.web.struts.ActionSupport，我们只要把自己的Action继承自ActionSupport，就是可以调用ActionSupport中getWebApplicationContext()的方法取出WebApplicationContext，但这样一来在Action中，需要取得业务逻辑的地方都要getBean，看上去不够简洁，所以Spring又提供了另一个方法，用org.springframework.web.struts.ContextLoaderPlugIn，这是一个Struts的Plug，在Struts启动时加载，对于Action，可以像管理Bean一样来管理，在struts-config.xml中Action的配置变成类似下面的样子<br />
&lt;action  attribute=&#8221;aForm&#8221; name=&#8221;aForm&#8221; path=&#8221;/aAction&#8221;  scope=&#8221;request&#8221;  type=&#8221;org.springframework.web.struts.DelegatingActionProxy&#8221;&gt;<br />
&lt;forward name=&#8221;forward&#8221; path=&#8221;forward.jsp&#8221;  /&gt;<br />
&lt;/action&gt;<br />
注意type变成了org.springframework.web.struts.DelegatingActionProxy，之后我们需要建立action-servlet.xml这样的文件，action-servlet.xml符合Spring的spring-beans.dtd标准，在里面定义类似下面的<br />
&lt;bean  name=&#8221;/aAction&#8221; class=&#8221;com.web.action.Aaction&#8221; singleton=&#8221;false&#8221;&gt;<br />
&lt;property name=&#8221;businessService&#8221;&gt;<br />
&lt;ref  bean=&#8221;businessService&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>com.web.action.Aaction是Action的实现类，businessService是需要的业务逻辑，Spring会把businessService注入到Action中，在Action中只要写businessService的get和set方法就可以了，还有一点，action的bean是singleton=&#8221;false&#8221;，即每次新建一个实例，这也解决了Struts中Action的线程同步问题，具体过程是当用户做“/aAction”的HTTP请求（当然应该是“/aAction.do”），Struts会找到这个Action的对应类org.springframework.web.struts.DelegatingActionProxy，DelegatingActionProxy是个代理类，它会去找action-servlet.xml文件中“/aAction”对应的真正实现类，然后把它实例化，同时把需要的业务对象注入，然后执行Action的execute方法。</p>
<p>使用了ContextLoaderPlugIn，在struts-config.xml中变成类似这样配置<br />
&lt;plug-in  className=&#8221;org.springframework.web.struts.ContextLoaderPlugIn&#8221;&gt;<br />
&lt;set-property property=&#8221;contextConfigLocation&#8221;  value=&#8221;/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml&#8221;  /&gt;<br />
&lt;/plug-in&gt;<br />
而在web.xml中不再需要ContextLoaderListener或是ContextLoaderServlet。</p>
<p>说到这里不知道大家会不会有这样的问题，如果使用ContextLoaderPlugIn，如果我们有些程序是脱离Struts的Action环境，我们怎么处理，比如我们要自定义标记库，在标记库中，我们需要调用Spring管理的业务层逻辑对象，这时候我们就很麻烦，因为只有在action中动态注入业务逻辑，其他我们似乎不能取得Spring的WebApplicationContext。</p>
<p>别急，我们还是来看一下ContextLoaderPlugIn的源码（源码不再贴出），我们可以发现，原来ContextLoaderPlugIn仍然是把WebApplicationContext放在ServletContext中，只是这个KEY不太一样了，这个KEY值为ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX+ModuleConfig.getPrefix()（具体请查看源代码），这下好了，我们知道了WebApplicationContext放在哪里，只要我们在Web应用中能够取到ServletContext也就能取到WebApplicationContext了:)</p>
]]></content:encoded>
			<wfw:commentRss>http://i.laoer.com/spring-applicationcontext.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
