在Spring IOC-Servlet加载到bean工厂一文中说明了Spring是如何将servlet bean加载到bean工厂中,这里的servlet bean相当于是Control层,而本文中要介绍的bean可以理解为Service层和Dao层的bean,当然这样划分只是便于理解,实际中不会局限这些,可以是任何你定义的bean。
其实这里的加载过程类似servlet加载过程,只不过两者的触发不一样,servlet bean加载是在工程启动时候初始化web.xml中定义的Servlet触发的,贴出在web.xml中的配置:
<servlet>
<servlet-name>citic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/frm-servlet.xml,/WEB-INF/app-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
而触发业务bean 的配置如下
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-beans.xml</param-value>
</context-param>
所以加载业务bean的工作就在ContextLoaderListener这个类的具体实现中。
两者在工程启动时候的加载顺序是:ContextLoaderListener在先,因为ContextLoaderListener加载的bean相当于低层次的bean,是要被高层次的Servlet bean调用的,空说无凭,有项目启动日志为证。
在ContextLoaderListener初始化的时候回调contextInitialized方法,方法代码如下:
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;//就是父类,就是自己
}
//在这里就会进行Spring环境的加载,bean工厂
this.contextLoader.initWebApplicationContext(event.getServletContext());
contextLoader的初始化过程关键代码如下:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
………………
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext);
}
………………
然后定位代码到configureAndRefreshWebApplicationContext方法,关键代码如下:
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
………………
String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (initParameter != null) {
wac.setConfigLocation(initParameter);
}
customizeContext(sc, wac);
wac.refresh();
………………
在这里我们看到了wac.refresh();
代码,这行代码有似曾相识的感觉,就是在Spring IOC-Servlet加载到bean工厂最后留下的悬念,因为refresh的过程非常复杂,所以统一在《Spring IOC-WebApplicationContext刷新》一文中分享说明。