我们知道,在开发基于Spring的Web应用时,通常使用两个IoC容器,一个是由DispatchServlet初始化的WebApplicationContext,一个是由ContextLoaderListener初始化的ApplicationContext。对于Spring容器,Spring的官方参考手册详细地讲解了依赖注入的配置方式,对于容器本身的配置和多个容器之间的关系却不曾提及。于是,很多人以为在一个应用中只有一个全局的Spring容器,或者不了解MVC使用的WebApplicationContext和根ApplicationContext的关系。
通过查看Spring的源码和API,发现Spring可以配置为多个容器,容器之间可以配置为层级关系,一个根容器可以配置许多子容器,子容器还可以配置子容器,从而形成一个单根的层次化结构。对于该容器结构中的每个容器,在其中查找特定的bean时,会首先在本容器内查找,如果找到对应的bean,就返回该bean;如果没有找到,就会从直接父容器中去查找,依此类推,直到根容器为止。
下面是一个例子:
配置文件1:SpringXMLConfig1
</pre><p><pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
">
<bean id="all" class="java.lang.String">
<constructor-arg type="String" value="the parent context"/>
</bean>
<bean id="parent" class="java.lang.String">
<constructor-arg type="String" value="Only in the parent context"/>
</bean>
</beans>
配置文件2:SpringXMLConfig2
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
">
<bean id="all" class="java.lang.String">
<constructor-arg type="String" value="the child context"/>
</bean>
<bean id="child" class="java.lang.String">
<constructor-arg type="String" value="Only in the child context"/>
</bean>
</beans>
测试类:TestSpringParent
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author Administrator
*/
public class TestSpringParent {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ApplicationContext ac1=
new ClassPathXmlApplicationContext(
"SpringXMLConfig1.xml",test.TestSpringParent.class);
ApplicationContext ac2=
new ClassPathXmlApplicationContext(
new String[]{"SpringXMLConfig2.xml"},test.TestSpringParent.class,ac1);//ac2配置为ac1的子容器
String all1=ac1.getBean("all",String.class); //父容器中取得同名bean
String all2=ac2.getBean("all",String.class); //子容器中取得同名bean
String a1=ac2.getBean("parent",String.class); //子容器中取父容器中配置的bean
String a2=ac2.getBean("child", String.class); //子容器中取子容器中配置的bean
//String a3=ac1.getBean("child", String.class); //父容器中取子容器中配置的bean 此行会产生异常!
System.out.println("父容器中取得同名bean:"+all1);
System.out.println("子容器中取得同名bean:"+all2);
System.out.println("子容器中取父容器中配置的bean:"+a1);
System.out.println("子容器中取子容器中配置的bean:"+a2);
}
}
从上面的示例中可以看到,从子容器中可以取得父容器中配置的bean,而父容器中不能够取得子容器中的bean。
在Spring MVC中WebApplicationContext配置为根ApplicationContext的子容器,所以,MVC使用的容器中能够取得根ApplicationContext中的bean。在一个web程序中可以配置多个DispatchSerlvet,每个Servlet对应一个容器,所有这些容器都作为根容器的子容器,这样,我们就可以把通用的bean放在根容器中,而针对特定DispatchServlet的bean,可以放在各自的子容器中。