一.什么是IOC?
IOC就是将原先在客户端实现的对象的创建和对象依赖的任务反转给容器来实现。
这就要求我们要实现一个容器,并将容器需要创建的对象及对象间的依赖关系描述出来,由这个容器来实现对象的创建及初始化工作。对象的描述和依赖关系可以采用xml,properties文件和注解来完成。IOC容器的主要职责是对象的创建和依赖的管理注入。
二.Spring IOC容器的体系结构
2.1 BeanFactory
Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,
2.1.1 BeanFactory的继承体系
其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为.
最基本的IOC容器接口BeanFactory
2.2 ApplicationContext
在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。
而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述),如果说XmlBeanFactory是容器中的屌丝,ApplicationContext应该算容器中的高帅富.
ApplicationContext是Spring提供的一个高级的IoC容器,它除了能够提供IoC容器的基本功能外,还为用户提供了以下的附加服务。
从ApplicationContext接口的实现,我们看出其特点:
1. 支持信息源,可以实现国际化。(实现MessageSource接口)
2. 访问资源。(实现ResourcePatternResolver接口)
3. 支持应用事件。(实现ApplicationEventPublisher接口)
2.2.1 ApplicationContext的继承体系
ApplicationContext允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。
2.3.BeanDefinition
SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的,spring会将配置文件中的bean解析成BeanDefinition,其继承体系如下:
三.IOC容器的初始化
IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。我们以ApplicationContext为例讲解,系列容器也许是我们最熟悉的,因为web项目中使用的XmlWebApplicationContext就属于这个继承体系,还有ClasspathXmlApplicationContext等,
3.1 XmlBeanFactory容器的流程
通过XmlBeanFactory的源码,我们可以发现:
三.IOC容器的初始化
IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。我们以ApplicationContext为例讲解,系列容器也许是我们最熟悉的,因为web项目中使用的XmlWebApplicationContext就属于这个继承体系,还有ClasspathXmlApplicationContext等,
3.1 XmlBeanFactory容器的流程
通过XmlBeanFactory的源码,我们可以发现:
一个简单的加载示例:
通过前面的源码,this.reader = new XmlBeanDefinitionReader(this); 中其中this 传的是factory对象
1.2 XmlWebApplicationContext容器的流程
3.2.1web.xml注册ContextLoaderListener
1)注册contextConfigLocation
在web.xml文件中注册参数,用于标记一组spring配置文件的位置。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/applicationContext.xml,classpath*:/application-dubbo.xml
,classpath*:/search-mq-provider.xml,classpath*:/search-mq-consumer.xml
,classpath*:/app-context-mq.xml
</param-value>
</context-param>
2)注册ContextLoaderListener
首先在web.xml文件中注册ContextLoaderListener,该类的作用是servlet容器启动及关闭时,做为监听器处理spring容器的启动和销毁
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3.2.2 容器启动阶段流程
3.2.2.1 容器启动----ContextLoader捕获Servlet容器启动事件,调用contextInitialized方法
ContextLoader实现了ServletContextListener接口,当Servlet容器启动时,contextInitialized方法会调用,在此方法中初始化WebApplicationContext。
public class ContextLoaderListener extendsContextLoader implements ServletContextListener {
/**省略部分代码 **/
/**
* Initialize the root web application context.
*/
@Override
publicvoid contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
publicvoid contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
3.2.2.2 初始化上下文---initWebApplicationContext(ServletContext servletContext)
CotextLoader.java中initWebApplicationContext方法用来初始化ApplicationContext。
在这个方法里,经过一系列的初始化处理后,调用createWebApplicationContext(ServletContext sc)创建spring上下文类,并实例化。
createWebApplicationContext源码如下:
/**
* Initialize Spring's web application contextfor the given servlet context,
* using the application context provided atconstruction time, or creating a new one
* according to the "{@link#CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAMcontextConfigLocation}" context-params.
* @param servletContext current servletcontext
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
publicWebApplicationContext initWebApplicationContext(ServletContext servletContext){
if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)!= null) {
thrownew IllegalStateException(
"Cannotinitialize context because there is already a root application context present- " +
"checkwhether you have multiple ContextLoader* definitions in your web.xml!");
}
Loglogger = LogFactory.getLog(ContextLoader.class);
servletContext.log("InitializingSpring root WebApplicationContext");
if(logger.isInfoEnabled()) {
logger.info("RootWebApplicationContext: initialization started");
}
longstartTime = System.currentTimeMillis();
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) {
ConfigurableWebApplicationContextcwac = (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.
ApplicationContextparent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac,servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);
ClassLoaderccl = Thread.currentThread().getContextClassLoader();
if(ccl == ContextLoader.class.getClassLoader()) {
currentContext= this.context;
}
elseif (ccl != null) {
currentContextPerThread.put(ccl,this.context);
}
if(logger.isDebugEnabled()) {
logger.debug("Publishedroot WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE+ "]");
}
if(logger.isInfoEnabled()) {
longelapsedTime = System.currentTimeMillis() - startTime;
logger.info("RootWebApplicationContext: initialization completed in " + elapsedTime +" ms");
}
returnthis.context;
}
catch(RuntimeException ex) {
logger.error("Contextinitialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ex);
throwex;
}
catch(Error err) {
logger.error("Contextinitialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,err);
throwerr;
}
}
public WebApplicationContextinitWebApplicationContext(ServletContext servletContext) {
if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)!= null) {
thrownew IllegalStateException(
"Cannotinitialize context because there is already a root application context present- " +
"checkwhether you have multiple ContextLoader* definitions in your web.xml!");
}
Loglogger = LogFactory.getLog(ContextLoader.class);
servletContext.log("InitializingSpring root WebApplicationContext");
if(logger.isInfoEnabled()) {
logger.info("RootWebApplicationContext: initialization started");
}
longstartTime = System.currentTimeMillis();
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) {
ConfigurableWebApplicationContextcwac = (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.
ApplicationContextparent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac,servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);
ClassLoaderccl = Thread.currentThread().getContextClassLoader();
if(ccl == ContextLoader.class.getClassLoader()) {
currentContext= this.context;
}
elseif (ccl != null) {
currentContextPerThread.put(ccl,this.context);
}
if(logger.isDebugEnabled()) {
logger.debug("Publishedroot WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE+ "]");
}
if(logger.isInfoEnabled()) {
longelapsedTime = System.currentTimeMillis() - startTime;
logger.info("RootWebApplicationContext: initialization completed in " + elapsedTime +" ms");
}
returnthis.context;
}
catch(RuntimeException ex) {
logger.error("Contextinitialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ex);
throwex;
}
catch(Error err) {
logger.error("Contextinitialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,err);
throwerr;
}
})
3.2.2.3 创建应用上下文-createWebApplicationContext(ServletContext sc)
在createWebApplicationContext中获取application上下文的class,并实例化。
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
//获取application上下文的class
Class<?>contextClass = determineContextClass(sc); If(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw newApplicationContextException("Custom contextclass [" + contextClass.getName()+"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
其中determineContextClass(sc)方法返回application上下文的class,该class的来源有两处。初始化时首先会查找是否存在自定义的实现ConfigurableWebApplicationContext接口的WebApplicationContext实现类,该属性设置在web.xml文件中。如果不存在,则使用spring的默认配置。该配置存储在spirng的ContextLoader.properties配置文件中。具体解释如下:
1)contextClass :
初始化时,会先在web.xml中<context-param>中查找有没有一个叫做contextClass的配置。这个配置是用于自定义WebApplicationContext的实现类(自定义的WebApplicationContext的实现类,必须实现ConfigurableWebApplicationContext接口
2) ContextLoader.properties注册的org.springframework.web.context.WebApplicationContext属性指定的class路径
ContextLoader.properties如下:
# Default WebApplicationContextimplementation class for ContextLoader.
# Used as fallback when noexplicit context implementation has been specified as context-param.
# Not meant to be customized byapplication developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
determineContextClass(sc)具体代码如下:
/**
* Return the WebApplicationContextimplementation class to use, either the
* default XmlWebApplicationContext or a customcontext class if specified.
* @param servletContext current servletcontext
* @return the WebApplicationContextimplementation class to use
* @see #CONTEXT_CLASS_PARAM
* @seeorg.springframework.web.context.support.XmlWebApplicationContext
*/
protectedClass<?> determineContextClass(ServletContext servletContext) {
StringcontextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if(contextClassName != null) {
try{
returnClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch(ClassNotFoundException ex) {
thrownew ApplicationContextException(
"Failedto load custom context class [" + contextClassName + "]", ex);
}
}
else{
//defaultStrategies在ContextLoader.java静态块中被设置默认值,这里进行应用
contextClassName=defaultStrategies.getProperty(WebApplicationContext.class.getName());
try{
returnClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch(ClassNotFoundException ex) {
thrownew ApplicationContextException(
"Failedto load default context class [" + contextClassName + "]", ex);
}
}
}
3.2.2.4 XmlWebApplicationContext初始化
XmlWebApplicationContext通过BeanUtils.instantiateClass(contextClass)实例化
3.2.2.5 根据配置加载下文---refresh()
AbstractApplicationContext.java的refresh()方法根据配置加载或刷新上下文
@Override
public void refresh() throws BeansException,IllegalStateException {
synchronized (this.startupShutdownMonitor){
// 1.Prepare this context for refreshing.
prepareRefresh();
// 2.Tell the subclass to refresh the internal beanfactory.
ConfigurableListableBeanFactorybeanFactory= obtainFreshBeanFactory();
//3. Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//4. Allows post-processing of the bean factory incontext subclasses.
postProcessBeanFactory(beanFactory);
//5. Invoke factory processors registered as beans in thecontext.
invokeBeanFactoryPostProcessors(beanFactory);
//6. Register bean processors that intercept beancreation.
registerBeanPostProcessors(beanFactory);
//7. Initialize message source for this context.
initMessageSource();
//8. Initialize event multicaster for thiscontext.
initApplicationEventMulticaster();
//9. Initialize other special beans in specific contextsubclasses.
onRefresh();
//10. Check for listener beans and register them.
registerListeners();
//11. Instantiate all remaining (non-lazy-init)singletons.
finishBeanFactoryInitialization(beanFactory);
//12. Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization- " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid danglingresources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core,since we
//13. might not ever need metadata for singletonbeans anymore...
resetCommonCaches();
}
}
}
3.2.2.5.1 预处理-----prepareRefresh()
prepareRefresh函数主要是做些准备工作,设置日志时间,激活和关闭状态,对系统属性及环境变量的初始化及验证。
可以集成AbstractApplicationContext重写initPropertySources增加系统属性。同时在重写Environment的validateRequiredProperties()方法对该属性进行验证。
/**
* Prepare this context for refreshing, settingits startup date and
* active flag as well as performing anyinitialization of property sources.
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()){
logger.info("Refreshing "+ this);
}
// Initialize any placeholder property sources in thecontext environment
//子类可覆盖,增加属性源
initPropertySources();
// Validate that all properties marked as required areresolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//用于验证属性
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster isavailable...
this.earlyApplicationEvents= newLinkedHashSet<ApplicationEvent>();
}
3.2.2.5.2 ApplicationContext获取BeanFacotry----obtainFreshBeanFactory
obtainFreshBeanFactory()方法,首先关闭已存在的BeanFactory,并初始化一个新的BeanFactory,最后返回最新创建的BeanFacotry实例。的具体代码如下:
/**
* Tell the subclass to refresh the internalbean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protectedConfigurableListableBeanFactory obtainFreshBeanFactory() {
//关闭已存在的BeanFactory,并初始化一个新的BeanFactory
refreshBeanFactory();
ConfigurableListableBeanFactorybeanFactory = getBeanFactory();
if(logger.isDebugEnabled()) {
logger.debug("Beanfactory for " + getDisplayName() + ": " + beanFactory);
}
returnbeanFactory;
}
3.2.2.5.2.1 新建BeanFacotry---refreshBeanFactory()
obtainFreshBeanFactory方法的核心是refreshBeanFactory(),该方法真正的关闭已存在的BeanFactory,并初始化一个新的BeanFactory。具体代码如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果ApplicationContext中已经存在BeanFacgory,则关闭
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactorybeanFactory= createBeanFactory();
//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
//定制Beanfactory,设置是否支持覆盖已有属性的内容及是否支持循环依赖
customizeBeanFactory(beanFactory);
//加载bean定义
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor){
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw newApplicationContextException("I/O errorparsing bean definition source for "+ getDisplayName(), ex);
}
}
3.2.2.5.2.1.1设置是否支持覆盖已有属性的内容及是否支持循环依赖--- customizeBeanFactory()
customizeBeanFactory用于设置是否支持覆盖已有属性的内容及是否支持循环依赖。
Spring提供的扩展机制,子类可以重写allowBeanDefinitionOverriding和allowCircularReferences属性来达到控制容器是否支持覆盖已有属性和是否支持循环依赖的能力
customizeBeanFactory方法的代码如下:
protected void customizeBeanFactory(DefaultListableBeanFactorybeanFactory){
if (this.allowBeanDefinitionOverriding!= null){
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences!= null){
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
3.2.2.5.2.1.2加载BeanDefinition—loadBeanDefinitions(DefaultListableBeanFactorybeanFactory)
在loadBeanDefinitions方法中首先要做的就是初始化XmlBeanDefinitonReader.在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所以XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefinitionListableBeanFactory中,也就是经过这个步骤,DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。
loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
/**
* Loads the bean definitions via anXmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected voidloadBeanDefinitions(DefaultListableBeanFactory beanFactory) throwsBeansException, IOException {
// Create a new XmlBeanDefinitionReaderfor the given BeanFactory.
XmlBeanDefinitionReaderbeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definitionreader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
// Allow a subclass to providecustom initialization of the reader,
// then proceed with actuallyloading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
//加载配置文件中的bean定义,调用DefaultListableBeanFactory的registerBeanDefinition将bean定义封装到其beanDefinitionMap属性中
loadBeanDefinitions(beanDefinitionReader);
}
其中loadBeanDefinitions(XmlBeanDefinitionReader reader)代码如下:
protected voidloadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
//获取配置文件路径
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations){
reader.loadBeanDefinitions(configLocation);
}
}
}
DefaultListableBeanFactory的registerBeanDefinition(StringbeanName, BeanDefinition beanDefinition)方法源代码
@Override
public voidregisterBeanDefinition(String beanName, BeanDefinition beanDefinition)
throwsBeanDefinitionStoreException {
Assert.hasText(beanName,"Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinitionmust not be null");
if (beanDefinition instanceofAbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
}
catch (BeanDefinitionValidationExceptionex) {
throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validationof bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if(!isAllowBeanDefinitionOverriding()) {
throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannotregister bean definition [" + beanDefinition + "] for bean '" + beanName+
"': There isalready [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole()< beanDefinition.getRole()) {
// e.g. wasROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()){
this.logger.warn("Overridinguser-defined bean definition for bean '" + beanName +
"' witha framework-generated bean definition: replacing [" +
oldBeanDefinition+ "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)){
if (this.logger.isInfoEnabled()){
this.logger.info("Overridingbean definition for bean '" + beanName +
"' witha different definition: replacing [" + oldBeanDefinition +
"] with[" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()){
this.logger.debug("Overridingbean definition for bean '" + beanName +
"' withan equivalent definition: replacing [" + oldBeanDefinition +
"] with[" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName,beanDefinition);
}
else {
if (hasBeanCreationStarted()){
// Cannot modifystartup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap){
this.beanDefinitionMap.put(beanName,beanDefinition);
List<String> updatedDefinitions= new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames= updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)){
Set<String>updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames= updatedSingletons;
}
}
}
else {
// Still in startupregistration phase
this.beanDefinitionMap.put(beanName,beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames= null;
}
if (oldBeanDefinition != null ||containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
3.2.2.5.3 配置BeanFactory的标准特性---prepareBeanFactory(ConfigurableListableBeanFactorybeanFactory)
protectedvoid prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//Tell the internal bean factory to use the context's class loader etc.
//设置beanFactory的classLoader为当前context的classloader
beanFactory.setBeanClassLoader(getClassLoader());
//设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,
//默认可以使用#{bean.xxx}的形式来调用相关属性值
beanFactory.setBeanExpressionResolver(newStandardBeanExpressionResolver());
//为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(newResourceEditorRegistrar(this, getEnvironment()));
//Configure the bean factory with context callbacks.
/*
* 添加BeanPostProcessor,
*/
beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));
//设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
//BeanFactory interface not registered as resolvable type in a plain factory.
//MessageSource registered (and found for autowiring) as a bean.
//设置了几个自动装配的特殊 规则
beanFactory.registerResolvableDependency(BeanFactory.class,beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class,this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class,this);
beanFactory.registerResolvableDependency(ApplicationContext.class,this);
//Detect a LoadTimeWeaver and prepare for weaving, if found.
//增加对AspectJ的支持
if(beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));
//Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//Register default environment beans.
//添加默认的系统环境bean
if(!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME,getEnvironment());
}
if(!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME,getEnvironment().getSystemProperties());
}
if(!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME,getEnvironment().getSystemEnvironment());
}
}
3.5.2.2.5.3.1增加SPEL语言支持
Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,类似于Struts 2x中使用的OGNL语言,SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。
SpEL使用#{...}作为定界符,所有在大框号中的字符都将被认为是SpEL,使用格式如下:
<util:propertiesid="db" location="classpath:db.properties">
</util:properties>
<beanid="dbcp"class="org.apache.commons.dbcp.BasicDataSource">
<property name="username"value="#{db.user}"></property>
<property name="password"value="#{db.pwd}"></property>
<property name="driverClassName"value="#{db.driver}"></property>
<property name="url"value="#{db.url}"></property>
</bean>
上面只是列举了其中最简单的使用方式,SpEL功能非常强大,使用好可以大大提高开发效率。
在源码中通过代码beanFactory.setBeanExpressionResolver(newStandardBeanExpressionResolver()),注册语言解析器,就可以对SpEL进行解析了,那么之后是在什么地方调用这个解析器的呢?
之前说beanFactory中说过Spring在bean进行初始化的时候会有属性填充的一步,而在这一步中Spring会调用AbstractAutowireCapabelBeanFactory类的applyPropertyValues来进行属性值得解析。同时这个步骤中一般通过AbstractBeanFactory中的evaluateBeanDefinitionString方法进行SpEL解析:
protectedObject evaluateBeanDefinitionString(String value, BeanDefinitionbeanDefinition) {
if(this.beanExpressionResolver == null) {
returnvalue;
}
Scopescope = (beanDefinition != null ? getRegisteredScope(beanDefinition.getScope()): null);
returnthis.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this,scope));
}
当调用这个方法时会判断是否有语言解析器,如果存在则调用语言解析器,解析的过程在Spring的expression包里。
3.5.2.2.5.3.2.添加ApplicationContextAwareProcessor处理器
publicObject postProcessBeforeInitialization(final Object bean, String beanName)throws BeansException {
AccessControlContextacc = null;
if(System.getSecurityManager() != null &&
(beaninstanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
beaninstanceof ResourceLoaderAware || bean instanceofApplicationEventPublisherAware ||
bean instanceofMessageSourceAware || bean instanceof ApplicationContextAware)) {
acc= this.applicationContext.getBeanFactory().getAccessControlContext();
}
if(acc != null) {
AccessController.doPrivileged(newPrivilegedAction<Object>() {
public Object run() {
invokeAwareInterfaces(bean);
returnnull;
}
},acc);
}
else{
invokeAwareInterfaces(bean);
}
returnbean;
}
privatevoid invokeAwareInterfaces(Object bean) {
if(bean instanceof Aware) {
if(bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if(bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(
newEmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
if(bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if(bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if(bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if(bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
}
postProcessBeforeInitialization方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,我们可以看出来,实现这些Aware接口的bean在被初始化之后,可以取得一些对应的资源。
3.5.2.2.5.3.3.设置忽略依赖
Spring将ApplicationContextAwareProcessor注册后,在invokeAwareInterfaces方法中间调用的Aware类已经不是普通的bean了,如ResourceLoaderAware,ApplicationEventPublisherAware等,那么当然需要在Spring做bean的依赖注入的时候忽略它们。而ignoreDependencyInterface的作用正是如此。
//设置了几个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
3.5.2.2.5.3.4 注册依赖
Spring中有忽略依赖的功能,也有注册依赖的功能。
//设置了几个自动装配的特殊 规则
beanFactory.registerResolvableDependency(BeanFactory.class,beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class,this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class,this);
beanFactory.registerResolvableDependency(ApplicationContext.class,this);
当注册了依赖解析后,例如当注册了对BeanFactory.class的解析后,当bean的属性注入的时候,一旦检测到属性为BeanFactory类型便会将beanFactory的实例注入进去。
可能有些朋友有些迷糊,为什么刚刚实现了接口又忽略依赖注入,刚忽略接口的依赖注入,下面又增加了注册依赖的功能?
因为在Spring加载bean的时候,还会将实现的接口依赖进去,因为是单例模式的,这些接口已经在spring的其他模块做了依赖处理,在此不需要重复依赖。
3.2.2.5.4 允许在上下文子段中对bean工厂进行后处理-- postProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)
子类可以重写postProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)进行扩张,AbstractRefreshableWebApplicationContext中重写了该方法用于在容器中注册request/session作用域
/**
* Register request/session scopes, a {@linkServletContextAwareProcessor}, etc.
*/
@Override
protected voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(newServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,this.servletContext, this.servletConfig);
}
3.2.2.5.5 执行BeanFacotoryPostProccessor---invokeBeanFactoryPostProcessors(beanFactory)
此处执行注册的BeanFacotoryPostProccessor的postProcessBeanFactory方法
3.2.2.5.6 注册BeanPostPrecceor--registerBeanPostProcessors(beanFactory)
此处注册实现BeanPostPrecceor接口的实现类
3.2.2.5.7 注册国际化信息的MessageSource接口-MessageSource
/**
* Initialize the MessageSource.
* Use parent's if none defined in thiscontext.
*/
protectedvoid initMessageSource() {
ConfigurableListableBeanFactorybeanFactory = getBeanFactory();
if(beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource= beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
//Make MessageSource aware of parent MessageSource.
if(this.parent != null && this.messageSource instanceofHierarchicalMessageSource) {
HierarchicalMessageSourcehms = (HierarchicalMessageSource) this.messageSource;
if(hms.getParentMessageSource() == null) {
//Only set parent context as parent MessageSource if no parent MessageSource
//registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if(logger.isDebugEnabled()) {
logger.debug("UsingMessageSource [" + this.messageSource + "]");
}
}
else{
//Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSourcedms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource= dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME,this.messageSource);
if(logger.isDebugEnabled()) {
logger.debug("Unableto locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"':using default [" + this.messageSource + "]");
}
}
}
3.2.2.5.8 初始化application广播---initApplicationEventMulticaster
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster ifnone defined in the context.
* @seeorg.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactorybeanFactory= getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster=
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster+ "]");
}
}
else {
this.applicationEventMulticaster= newSimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster withname '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default ["+ this.applicationEventMulticaster+ "]");
}
}
}
3.2.2.5.9 预留子类扩展(初始化特殊的bean)---onRefresh()
onRefresh()预留了子类的扩展能力,抽象类中为空方法
AbstractRefreshableWebApplicationContext中进行了重写,增加了主题能力的引入
/**
* Initialize the theme capability.
*/
@Override
protected void onRefresh() {
this.themeSource =UiApplicationContextUtils.initThemeSource(this);
}
3.2.2.5.10 注册ApplicationListener监听器-- registerListeners()
注册实现了ApplicationListener接口的实现类
/**
* Add beans that implement ApplicationListeneras listeners.
* Doesn't affect other listeners, which can beadded without being beans.
*/
protectedvoid registerListeners() {
//Register statically specified listeners first.
for(ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//Do not initialize FactoryBeans here: We need to leave all regular beans
//uninitialized to let post-processors apply to them!
String[]listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true,false);
for(String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent>earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents= null;
if(earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent :earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
3.2.2.5.11 完成上下文工厂中类的实例化---finishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory)
完成上下文工厂中类的实例化,finishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory),在此完成beanpostprocessor的处理和bean的实例化过程
/**
* Finish the initialization of this context'sbean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory){
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Initialize LoadTimeWeaverAware beans early to allowfor registering their transformers early.织入第三方模块
String[]weaverAwareNames= beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for typematching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, notexpecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
3.2.2.5.12 完成上下文初始化后的刷新--finishRefresh()
/**
* Finish the refresh of this context, invokingthe LifecycleProcessor's
* onRefresh() method and publishing the
* {@linkorg.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}