BeanFactory到WebApplicationContext的结构 以及bean和spring容器的关系

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了:)

posted on 2014-08-12 16:08  为努力骄傲  阅读(402)  评论(0编辑  收藏  举报

导航