Spring的Web启动是个神马原理呢,看了一天源代码,晚上自己动手写个Demo。Spring启动web容器时通过Servlet或者定义一个Listener来初始化自己的Ioc容器,还有一个DispatchServlet来给你的ActionBean中注入你所需要的类。
我定义一个类WebLoader 来继承org.springframework.web.context.ContextLoader并重写他的createWebApplicationContext方法,我只改源代码中的一句话 wac.setConfigLocation(sc.getInitParameter(“xcontextConfigLocation”));
这个wac是ConfigurableWebApplicationContext
Spring源代码中默认的是contextConfigLocation参数你每次需要这样定义
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/c1.xml</param-value>
</context-param>
现在我改了以后
Spring就在web.xml中找下面这个东西
<context-param>
<param-name>xcontextConfigLocation</param-name>
<param-value>WEB-INF/c2.xml</param-value>
</context-param>
c1.xml中定义一句话<bean id=”b1″ class=”com.Bean1″/>
c2.xml中定义一句话<bean id=”b2″ class=”com.Bean2″/>
然后我定义一个Servlet在web容器启动时自动加载
<servlet>
<servlet-name>Context</servlet-name>
<servlet-class>com.InitWeb</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
这个servlet的Init方法为
@Override
public void init() throws ServletException {
System.out.println(“Hei i am init”);
ServletContext sc = getServletContext();
WebApplicationContext parent=WebApplicationContextUtils.getWebApplicationContext(sc);
WebLoader loader=new WebLoader();
WebApplicationContext wac=loader.createWebApplicationContext(sc, parent);
System.out.println(wac.getBeanDefinitionCount());
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
super.init();
}
我在jsp中写
<%
WebApplicationContext wac = WebApplicationContextUtils
.getRequiredWebApplicationContext(getServletContext());
Bean1 b1 = (Bean1) wac.getBean(“b1”);
out.println(b1.getName()+”<br/>”);
Bean2 b2 = (Bean2) wac.getBean(“b2”);
out.println(b2.getName()+”<br/>”);
%>
输出结果为
I am Bean One!
I am Bean Two!
在Servlet中Web容器中的ApplicationContext被我重写了,原本按默认参数只加载了c1.xml中的bean,我把容器中的WebApplicationContext 提取出来作为c2.xml的parent创建一个新的WebApplicationContext然后加载到ServletContext现在web上下文中的applicationcontext就含有两个配置文件中的bean了。
归根到底Spring在web容器中注入的基本原理就是在web容器启动时初始化WebApplicationContext 存到ServletContext中去,用这WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE就可以读到当前的Ioc容器。