BeanFactory: Ioc 容器
ApplicationContext: Spring容器
WebApplicationContext需要ServletContext实例,也就是说它必须在拥有Web 容器的
前提下才能完成启动的工作。
Spring分别提供了用于启动WebApplicationContext的 Servlet和 Web容器监听器: org.springframework.web.context.ContextLoaderServlet;
org.springframework.web.context.ContextLoaderListener。
两者的内部都实现了启动 WebApplicationContext 实例的逻辑,我们只要根据 Web 容
器的具体情况选择两者之一,并在web.xml中完成配置就可以了。
1. 使用 ContextLoader Listener
<!确定配置文件的位置--〉<context-param><param-name>contextConfigLocation</param-name><!--此处可以列出多个Spring 的 XML 配置文件→<param-value>/WEB-INF/daoContext.xml/WEB-iNF/applicationContext.xml</param-value></context-param><!-- 应用启动时,自动加载listener,该 listener会读取上面确定的XML配置文件。然后创建ApplicationContext实例--〉<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
ContextLoaderListener 通过 Web 容器上下文参数 contextConfigLocation 获取 Spring 配
置文件的位置。用户可以指定多个配置文件,用逗号、空格或冒号分隔均可。对于未带资
源类型前缀的配置文件路径, WebApplicationContext默认这些路径相对于Web的部署根路
径。当然,我们可以采用带资源类型前缀的路径配置,如classpath:spring/*.xml,classpath:spring/*/*.xml,
和上面的配置是等效的。
2. 使用 ContextLoaderServlet
<servlet><!--确定Servlet 的名--><servlet-name>context</servlet-name><!--确定 Servlet对应的类--〉<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class><!--确定Servlet的启动级别--〉<load-on-startup>l</load-on-startup></servlet>
采用这种方式时,应将context 的启动级别设成最小,即最优先启动。因为ApplicationContext是整个应用的核心。
注意:在两种启动方式中,推荐采用第一种。因为根据Servlet2.4规范, listener比Servlet优先启动;关键问题是有些容器并不支持Serlet2.4规范,即不支持listener。支持 listener的容器有:
ApacheTomcat4.x 及更高版本。
Jetty4.x及更高版本。
Resin 2.1.8 及更高版本。
Orion2.0.2及更高版本。
BEAWebLogic8.1 SP3
不支持 listener 的容器有:
BEAWebLogicupto 8.1 SP2 及更低版本。
IBMWebSphere 5.x 及更低版本。
OracleOC4J9.0.3 及更低版本。
使用Spring容器以后,程序各元素之间的关系图:
Bean配置信息:定义了Bean的实现和依赖关系。
Spring容器根据 Bean配置信息在容器内部建立Bean注册表。
3.使用ContextLoaderPlugIn
上面我们介绍了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的配置变成类似下面的样子
<action attribute="aForm" name="aForm" path="/aAction" scope="request" type="org.springframework.web.struts.DelegatingActionProxy">
<forward name="forward" path="forward.jsp" />
</action>
注意type变成了org.springframework.web.struts.DelegatingActionProxy,之后我们需要建立action-servlet.xml这样的文件,action-servlet.xml符合Spring的spring-beans.dtd标准,在里面定义类似下面的
<bean name="/aAction" class="com.web.action.Aaction" singleton="false">
<property name="businessService">
<ref bean="businessService"/>
</property>
</bean>
com.web.action.Aaction是Action的实现类,businessService是需要的业务逻辑,Spring会把businessService注入到Action中,在Action中只要写businessService的get和set方法就可以了,还有一点,action的bean是singleton="false",即每次新建一个实例,这也解决了Struts中Action的线程同步问题,具体过程是当用户做“/aAction”的HTTP请求(当然应该是“/aAction.do”),Struts会找到这个Action的对应类org.springframework.web.struts.DelegatingActionProxy,DelegatingActionProxy是个代理类,它会去找action-servlet.xml文件中“/aAction”对应的真正实现类,然后把它实例化,同时把需要的业务对象注入,然后执行Action的execute方法。
使用了ContextLoaderPlugIn,在struts-config.xml中变成类似这样配置
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml" />
</plug-in>
而在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了:)
BeanFactory到WebApplicationContext的结构 以及bean和spring容器的关系