1,在web.xml中有
<listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
在这里配置了,spring的监听器
2,查看ContextLoaderListener 会发现 他继承了ContextLoader 实现了ServletContextListener接口
因此在该类的中有contextInitialized(ServletContextEvent event)方法,该方法调用了initWebApplicationContext(event.getServletContext())
3,initWebApplicationContext方法在ContextLoader类中,该方法中主要代码如下:
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
再来看上面这段代码:首先,判断该类中的context属性是否为空,如果为空创建context,使用createWebApplicationContext(servletContext);这个方法。
然后再看this.context 是不是ConfigurableWebApplicationContext 的子类,如果是则强制转换为ConfigurableWebApplicationContext,然后判断该对象是不是可用的,这个可用,源代码中的注释里有这样的解释:Determine whether this application context is active, that is, whether it has been refreshed at least once and has not been closed yet.
由此可以看出当最近刷新过或者没有bean被回收等的时候,该对象应该才是被激活的或者说可用的。这里理解的不是太准确还请大神指点。
如果不是可用的则进入if语句,判断Context的上级context 是不是为空,如果为空则加载上级Context使用loadParentContext(servletContext) 方法,然后设置上级Context,做完这些之后,再执行configureAndRefreshWebApplicationContext(cwac, servletContext); 该方法是初始化中主要的方法,bean的加载等都建在该类中进行,暂且不说。
然后将WebApplicationContext设置到servletContext中,这样就做到了,Spring 中的Context与Servlet中的Context的交互,再接着下来就是设置当前Context,将类加载器和当前WebApplicationContext对应的放在Map中。
再回头来看configureAndRefreshWebApplicationContext(cwac, servletContext);方法:还是在ContextLoader类中,在这个方法中,首先servletContext会初始化一个contextid,set给ConfigurableWebApplicationContext ,在这个方法中最重要的内容是下面的这段代码:
1 wac.setServletContext(sc);
2 String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
3 if (configLocationParam != null) {
4 wac.setConfigLocation(configLocationParam);
5 }
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
6 ConfigurableEnvironment env = wac.getEnvironment();
7 if (env instanceof ConfigurableWebEnvironment) {
8 ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
9 customizeContext(sc, wac);
10 wac.refresh();
在第2行 有CONFIG_LOCATION_PARAM 常量org.springframework.web.context.ContextLoader.CONFIG_LOCATION_PARAM = "contextConfigLocation"
从这里可以知道下面将开始加载Spring的配置文件了(Spring-Context.xml 或者别的名称)再往下看,到第9行这里,当webApplication中的属性参数都设置完成之后,
执行customizeContext这个方法,在该方法中有这样的代码:
for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
Class<?> initializerContextClass =
GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
if (initializerContextClass != null) {
Assert.isAssignable(initializerContextClass, wac.getClass(), String.format(
"Could not add context initializer [%s] since its generic parameter [%s] " +
"is not assignable from the type of application context used by this " +
"context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
wac.getClass().getName()));
}
this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
}
AnnotationAwareOrderComparator.sort(this.contextInitializers);
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
initializer.initialize(wac);
}
由此可以看到,在这里扫描了spring的配置文件,并且创建了配置文件中的bean和注解标注的Java bean,如果再跟进去就是BeanUtil中的内容,
是通过反射创建java bean的过程了,到此Spring的IOC的加载过程告一段落!!
如有错误的地方希望大神指出来!!!