最近在SVN上下载了Spring3.0的源码学习. 先介绍个人到现在对于Spring中IOC的认识吧.欢迎大家一起讨论,呵呵,别拍砖.
Spring的IOC的实现分为 1. 资源(Resource)定位 2.资源(Resource)载入 3.资源的解析 4.Bean的注册 5.getBean时对象依赖关系的注入.以最通常用的web项目开始
Spring通过web容器启动是通过org.springframework.web.context.ContextLoaderListener来实现的,其代码如下:
其对ContextLoader的继承及对ServletContextListener的实现使用了适配器模式.
现在看看contextLoader中的initWebApplicationContext方法.
//监听器的初始化方法.对web应用的上下文进行初始化
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext (event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
this.context = createWebApplicationContext(servletContext, parent);
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);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}//异常略...
}
对容器的初始化的过程主要是通过 this.context = createWebApplicationContext(servletContext, parent);
这句完成的..进入createWebApplicationContext方法
protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) {
//得到确定的class对象.determineContextClass中首先在web.xml中查询是否有配置contextclass的上下文.
//如果有配置,则根据所配置的对象得到其class对象.否则通过在ContextLoader.properties的
//org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
//得到XmlWebApplicationContext的class对象
Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
//ConfigurableWebApplicationContext为接口.
//通过反射将对象实例化.如果web.xml中未配置contextclass的话,实际上是XmlWebApplicationContext对象
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
// Assign the best possible id value.
if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
// Servlet <= 2.4: resort to name specified in web.xml, if any.
String servletContextName = sc.getServletContextName();
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(servletContextName));
}
else {
// Servlet 2.5's getContextPath available!
try {
String contextPath = (String) ServletContext.class.getMethod("getContextPath").invoke(sc);
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(contextPath));
}
catch (Exception ex) {
throw new IllegalStateException("Failed to invoke Servlet 2.5 getContextPath method", ex);
}
}
wac.setParent(parent);
wac.setServletContext(sc);
wac.setConfigLocation(sc.getInitParameter(CONFIG_LOCATION_PARAM));
customizeContext(sc, wac);
//容器初始化的入口
wac.refresh();
return wac;
}