这一段我主要去看看spring容器的创建,继续(一)的代码,我们看
if (this.context == null) { this.context = createWebApplicationContext(servletContext); }
创建容器
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { 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 wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); return wac; }
Class<?> contextClass = determineContextClass(sc);
既然要创建一个context,首先需要确定context是由什么类定义, 这一行就是获取context的类,我们点进去看
protected Class<?> determineContextClass(ServletContext servletContext) { String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); } } }
servletContext.getInitParameter
是取web.xml里的配置参数,意思就是先看看我们有没有自己定义context的类
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
如果我们定义了,直接返回这个class.
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
如果没有定义的话,去defaultStrategies里去取,WebApplicationContext的类名作为key
那么defaultStrategies里的值哪来的呢,我们ctrl+o,然后搜索defaultStrategies,会看到
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"; private static final Properties defaultStrategies; static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); } }
在类加载的时候,会去当前目录取这个属性文件
ContextLoader.properties
我们看看spring的jar包中,当前这个类是org.springframework.web.context.ContextLoader,那么我们就去web包的context路径下看
可以看到contextLoader.properties文件在这里,打开查看里面的配置,我们会发现spring在web工程中,默认使用的context,默认是xmlWebApplicationContext
看到这里我会建议最好先去看看xmlWebApplicationContext的上下继承关系,至少需要知道它具备哪些特性
有了大致的了解后再接着往下读
接着回到创建容器的代码里来
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { 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 wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); return wac; }
第一行我们知道了spring的web工程会首先取用户在web.xml里配置的context的类,如果用户配置了,就采用配置的,如果用户没有配置,就采用默认的xmlWebApplicationContext
接着进入第2行,不管采用配置的还是默认的,spring要求,必须是可配置的,也就是configurable.
只有是Configurable,才能进行后续的配置操作,至于Configurable的具体含义,我们后面会了解到。
现在紧接着
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
这个方法是用xmlWebApplicationContext的类作为参数,调用它的无参构造,实例一个对象,也就是我们期待已久的spring容器对象,至此,spring容器创建了
接下来在(三)里,我们去学习填充容器的过程,包括它是怎么配置的,还有最重要的,它是怎么刷新的,“刷新”这个动作就是将spring的xml配置变成bean,这个是ioc的核心,会涉及到一系列 beans包和core包,还有io包下的东西,所以建议一起学习的朋友在看下去之前,先随便了解一些bean包的相关结构和知识。