Spring学习(三):Spring源码解读启动过程及IOC原理

在Web容器中启动Spring IOC

ContextLoaderListener实现ServletContextListener,这个接口里面的函数会结合web容器的生命周期被调用。因为ServletContextListener是ServletContext的监听者,如果ServletContext发生变化,会触发相应的事件,而监听者一直对这些事件进行监听,如果接受到了监听的事件,就会作出预先设计好的动作。例如在服务器启动,ServletContext被创建的时候,ServletContextListener的contextInitialized()方法被调用,从而拉开了初始化Spring IOC容器的大幕。

 

 

首先从Servlet的启动事件中得到ServletContext,然后读取web.xml中的各个相关的属性值,接着ContextLoader会实例化WebApplicationContext,并完成载入和初始化的过程,这个被初始化的第一个上下文作为根上下文而存在,这个根上下文载入后,被绑定到web应用程序的ServletContext上,这样,IOC容器中的类就可以在任何地方访问到了。

具体的Ioc容器的载入过程在refresh()中实现,这个方法主要干了以下几件事情:

(1)Resource文件的定位,即找到bean的配置文件

(2)通过特定的reader解析该bean配置文件,抽象成beanDefinition类

(3)将beanDefinition向容器注册,写入到一个大的HashMap中,供实例化请求的时候使用

Ioc容器的初始化是由refresh()方法来启动的,这个方法标志着Ioc容器的正式启动。

具体来说这个启动过程包括三个基本过程,需要注意的是,Spring把这三个过程分开,并使用不同的模块来完成,如使用相应的ResourceLoader、BeanDifinitionReader等模块,通过这样的实际方式,可以让用户更加灵活的对这三个过程进行剪裁和扩展。

定义出最适合自己的Ioc容器的初始化过程。

第一个过程:BeanDifinition的Resource定位

这个Resource定位指的是BeanDifinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDifinition的使用都提供了统一的接口。

对于这些BeanDifinition的存在形式,相信大家都不会感到陌生。比如,

在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象。

在类路劲中的Bean定义信息可以使用ClassPathResource。

这个定位过程类似于容器寻找数据的过程,就想水桶装水先要把水找到一样。

第二个过程:BeanDifinition的载入

这个载入过程是把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDifinition。具体来说,BeanDifinition实际上就是POJO对象在IOC容器中的抽象,通过这个BeanDifinition定义的数据结构,使IOC容器能够方便的对POJO对象也就是Bean进行管理。

第三个过程:BeanDifinition的注册

这个操作是通过调用BeanDifinitionRegistry借口来实现的。这个注册过程把载入过程中解析得到的BeanDifinition向Ioc容器进行注册。在阅读源码中可知,在IOC容器内部将BeanDifinition注入到一个HashMap中去,Ioc容器就是通过这个HashMap来持有这些BeanDifinition数据的。

这里说到的Ioc容器的初始化过程,一般不包含Bean依赖注入的实现。在Ioc的设计中,Bean定义的载入和依赖注入是俩个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。(使用预实例化的配置除外)。下面详细讲解一下springIOC容器的初始化过程。

 

IoC容器的初始化

一般来说,注册bean的基本流程为:

  1. 加载资源文件生成Resource对象
  2. 解析Resource对象(包含XML的各种标签元素)生成BeanDefinitionHold对象
  3. 根据解析后的BeanDefinitionHold对象进行注册

   IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。我们主要以ApplicationContext为例讲解,ApplicationContext系列容器也许是我们最熟悉的,因为web项目中使用的XmlWebApplicationContext就属于这个继承体系,还有ClasspathXmlApplicationContext等

ApplicationContext允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。

 下面我们分别简单地演示一下两种ioc容器的创建过程

下面我们分别简单地演示一下DefaultListableBeanFactory和FileSystemXmlApplicationContext 两种ioc容器的创建过程

DefaultListableBeanFactory实现流程

XmlBeanFactory在3.1以后已经被废弃,不再推荐使用

/根据Xml配置文件创建Resource资源对象,该对象中包含了BeanDefinition的信息
 ClassPathResource resource =new ClassPathResource("application-context.xml");
//创建DefaultListableBeanFactory
 DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
//创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数
//,是因为会将读取的信息回调配置给factory
 XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。
//完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用
 reader.loadBeanDefinitions(resource);

FileSystemXmlApplicationContext实现流程

类信息:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext{}

1.先调用构造函数

ApplicationContext=new FileSystemXmlApplicationContext(xmlPath);

/**
创建一个FileSystemXmlApplicationContext上下文  从给予的XML文件加载definitions 然后自动刷新上下文 (Create a new FileSystemXmlApplicationContext, loading the definitions
* from the given XML files and automatically refreshing the context.)
* @param configLocations array of file paths
* @throws BeansException if context creation failed */
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null);}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  throws BeansException {    
        设置bean的资源加载器
        super(parent);  -->AbstractRefreshableConfigApplicationContext
                            -->AbstractApplicationContext
        bean资源文件定位路径
        setConfigLocations(configLocations);  
        if (refresh) {  
            refresh();  
        }  
    } 

2.设置资源加载器和资源定位

 通过分析FileSystemXmlApplicationContext的源代码可以知道,在创建FileSystemXmlApplicationContext容器时,构造方法做以下两项重要工作:

  • 首先,调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
  • 然后,再调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。

通过追踪FileSystemXmlApplicationContext的继承体系,发现其父类的父类AbstractApplicationContext中初始化IoC容器所做的主要源码如下:

public abstract class AbstractApplicationContext extends DefaultResourceLoader  
        implements ConfigurableApplicationContext, DisposableBean {  
    //静态初始化块,在整个容器创建过程中只执行一次  
    static {  
        //为了避免应用程序在Weblogic8.1关闭时出现类加载异常加载问题,加载IoC容  
       //器关闭事件(ContextClosedEvent)类  
        ContextClosedEvent.class.getName();  
    }  
    //FileSystemXmlApplicationContext调用父类构造方法调用的就是该方法  
    public AbstractApplicationContext(ApplicationContext parent) {  
        this.parent = parent;  
        this.resourcePatternResolver = getResourcePatternResolver();  
    }  
    //获取一个Spring Source的加载器用于读入Spring Bean定义资源文件  
    protected ResourcePatternResolver getResourcePatternResolver() {  
        // AbstractApplicationContext继承DefaultResourceLoader,也是一个  
        //Spring资源加载器,其getResource(String location)方法用于载入资源  
        return new PathMatchingResourcePatternResolver(this);  
    }   
……  
} 
Spring5.0源码
public AbstractApplicationContext() {
    this.logger = LogFactory.getLog(this.getClass());
    this.id = ObjectUtils.identityToString(this);
    this.displayName = ObjectUtils.identityToString(this);
    this.beanFactoryPostProcessors = new ArrayList();
    this.active = new AtomicBoolean();
    this.closed = new AtomicBoolean();
    this.startupShutdownMonitor = new Object();
    this.applicationListeners = new LinkedHashSet();
    this.resourcePatternResolver = this.getResourcePatternResolver();
}

public AbstractApplicationContext(@Nullable ApplicationContext parent) {
    this();
    this.setParent(parent);
}
public void setParent(@Nullable ApplicationContext parent) {
    this.parent = parent;
    if (parent != null) {
        Environment parentEnvironment = parent.getEnvironment();
        if (parentEnvironment instanceof ConfigurableEnvironment) {
            this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
        }
    }

}

 

AbstractApplicationContext构造方法中调用PathMatchingResourcePatternResolver的构造方法创建Spring资源加载器:

public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {  
        Assert.notNull(resourceLoader, "ResourceLoader must not be null");  
        //设置Spring的资源加载器  
        this.resourceLoader = resourceLoader;  
} 

在设置容器的资源加载器之后,接下来FileSystemXmlApplicationContet执行setConfigLocations方法通过调用其父类AbstractRefreshableConfigApplicationContext的方法进行对Bean定义资源文件的定位,该方法的源码如下:

 //处理单个资源文件路径为一个字符串的情况  
    public void setConfigLocation(String location) {  
       //String CONFIG_LOCATION_DELIMITERS = ",; /t/n";  
       //即多个资源文件路径之间用” ,; /t/n”分隔,解析成数组形式  
        setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));  
    }  

    //解析Bean定义资源文件的路径,处理多个资源文件字符串数组  
     public void setConfigLocations(String[] locations) {  
        if (locations != null) {  
            Assert.noNullElements(locations, "Config locations must not be null");  
            this.configLocations = new String[locations.length];  
            for (int i = 0; i < locations.length; i++) {  
                // resolvePath为同一个类中将字符串解析为路径的方法  
                this.configLocations[i] = resolvePath(locations[i]).trim();  
            }  
        }  
        else {  
            this.configLocations = null;  
        }  
    } 

通过这两个方法的源码我们可以看出,我们既可以使用一个字符串来配置多个Spring Bean定义资源文件,也可以使用字符串数组,即下面两种方式都是可以的:

  •  ClasspathResource res = new ClasspathResource(“a.xml,b.xml,……”);

多个资源文件路径之间可以是用” ,; /t/n”等分隔。

  •  ClasspathResource res = new ClasspathResource(newString[]{“a.xml”,”b.xml”,……});

至此,Spring IoC容器在初始化时将配置的Bean定义资源文件定位为Spring封装的Resource。

 

3、AbstractApplicationContext的refresh函数载入Bean定义过程:

  Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入

FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器对Bean定义的载入过程:

 public void refresh() throws BeansException, IllegalStateException {  
        synchronized (this.startupShutdownMonitor) {  
//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识  
 prepareRefresh();  
//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从子类的refreshBeanFactory()方法启动  
 ConfigurableListableBeanFactory beanFactory= obtainFreshBeanFactory();  
//为BeanFactory配置容器特性,例如类加载器、事件处理器等  
prepareBeanFactory(beanFactory);  
 try {  
//为容器的某些子类指定特殊的BeanPost事件处理器  
postProcessBeanFactory(beanFactory);  
//调用所有注册的BeanFactoryPostProcessor的Bean  
invokeBeanFactoryPostProcessors(beanFactory);  
//为BeanFactory注册BeanPost事件处理器.BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
registerBeanPostProcessors(beanFactory);  
//初始化信息源,和国际化相关.  
initMessageSource();  
//初始化容器事件传播器.  
initApplicationEventMulticaster();  
//调用子类的某些特殊Bean初始化方法  
onRefresh();  
//为事件传播器注册事件监听器.  
registerListeners();  
//初始化所有剩余的单态Bean.  
finishBeanFactoryInitialization(beanFactory);  
//初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
finishRefresh();  
            }  
            catch (BeansException ex) {  
                //销毁已创建的单态Bean  
                destroyBeans();  
                //取消refresh操作,重置容器的同步标识.  
                cancelRefresh(ex);  
                throw ex;  
            }  
       }  
    }

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory()

这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。

  refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化。

对Bean定义资源进行载入 AbstractApplicationContext的obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程,代码如下:

 

 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
        //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
         refreshBeanFactory();   
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
        if (logger.isDebugEnabled()) {  
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
        }  
        return beanFactory;  
    } 

loadBeanDefinition方法的大致过程如下:

加载资源文件

  1. 创建IOC容器并对IOC容器进行定制化
  2. 调用bean的定义方法,创建bean加载器并为加载器设置SAX XML解析器 启用XML校验机制
  3. 获取Bean定位资源 读取定义资源,获取IOC容器初始化设置的资源加载器,将bean资源文件解析为IOC容器封装的资源
  4. 获取资源文件的具体方法:
  • 如果是类路径用ClassPathResource来得到bean文件的资源对象
  • 如果是URL用URLResource来得到bean文件的资源对象
  • 如果都不是用FileSystemResource来得到bean文件的资源对象

加载完成 得到Resource对象

解析Resource对象

1.将读入的Resource对象进行特殊编码的处理

  • 将资源文件转为InputStream的IO流从InputStream获取解析对象->转2
  • 将Resource解析为DOM对象 创建文件工厂解析器 设置XML校验解析定位资源

2.按照Spring的bean语义要求将bean定义解析为容器内部结构

  • 获取容器中bean的数量
  • 得到BeanDefinitionDocumentReader 对XML格式的Document进行解析转3
  • 统计解析后的bean数量

3.根据Spring DTD对bean的定义规则解析bean定义的Document对象

  • 获取XML描述符 获得Document对象根元素
  • 解析Document 对<Import>、<Alias>元素进行解析
  • 解析<bean>元素
  • 解析<property>元素
  • 解析<property>子元素 包括<List>元素

解析完成 返回DefinitionHold对象

注册BeanDefinitionHold

1.解析过后的BeanDefinition向IOC容器注册

  • 获取解析后的Definition名称
  • 向IOC容器注册BeanDefinition 如果解析后的BeanDefinition有别名 向容器注册其别名转2

2.向IOC容器注册解析的BeanDefinition

  • 校验解析的BeanDefinition
  • 锁住beanDefinitionMap 注册过程需要线程同步 保持数据一致性
  • 注册过程中检查是否有同名的BeanDefinition

          有 不能覆盖 抛出异常

         有 能覆盖 覆

          没有 按正常流程注册

  • 重置所有已注册的BeanDefinition缓存

注册完成后 IOC容器初始化的所有工作都已完成 这些BeanDefinition信息可以被检索和使用

 

现在通过上面的代码,总结一下IOC容器初始化的基本步骤:

  • 初始化的入口在容器实现中的 refresh()调用来完成
  • 对 bean 定义载入 IOC 容器使用的方法是loadBeanDefinition()
  • 然后我们就可以通过 BeanFactory 和 ApplicationContext 来享受到 Spring IOC 的服务

在使用 IOC 容器的时候,我们注意到除了少量粘合代码,绝大多数以正确 IoC 风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。 Spring 本身提供了对声明式载入 web 应用程序用法的应用程序上下文,并将其存储在ServletContext 中的框架实现。

 

在使用 Spring IOC 容器的时候我们还需要区别两个概念:

  Beanfactory 和 Factory bean,其中 BeanFactory 指的是 IOC 容器的编程抽象,比如 ApplicationContext, XmlBeanFactory 等,这些都是 IOC 容器的具体表现,需要使用什么样的容器由客户决定,但 Spring 为我们提供了丰富的选择。 FactoryBean 只是一个可以在 IOC而容器中被管理的一个 bean,是对各种处理过程和资源使用的抽象,Factory bean 在需要时产生另一个对象,而不返回 FactoryBean本身,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的 Factory bean 都实现特殊的org.springframework.beans.factory.FactoryBean 接口,当使用容器中 factory bean 的时候,该容器不会返回 factory bean 本身,而是返回其生成的对象。Spring 包括了大部分的通用资源和服务访问抽象的 Factory bean 的实现,其中包括:对 JNDI 查询的处理,对代理对象的处理,对事务性代理的处理,对 RMI 代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING 为我们建立好的工厂。也就是说 Spring 通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在 IOC 容器里配置好就能很方便的使用了

 

IOC容器的依赖注入

1、依赖注入发生的时间

当Spring IoC容器完成了Bean定义资源的定位、载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生:

(1).用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。

(2).当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。

BeanFactory接口定义了Spring IoC容器的基本功能规范,是Spring IoC容器所应遵守的最底层和最基本的编程规范。BeanFactory接口中定义了几个getBean方法,就是用户向IoC容器索取管理的Bean的方法,我们通过分析其子类的具体实现,理解Spring IoC容器在用户索取Bean时如何完成依赖注入。

在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中

 

2、AbstractBeanFactory通过getBean向IoC容器获取被管理的Bean:

 依赖注入的过程

AbstractBeanFactory的getBean相关方法的源码如下

 

 //获取IoC容器中指定名称的Bean  
2    public Object getBean(String name) throws BeansException {  
3        //doGetBean才是真正向IoC容器获取被管理Bean的过程  
4        return doGetBean(name, null, null, false);  
5    }  
6    //获取IoC容器中指定名称和类型的Bean  
7    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {  
8        //doGetBean才是真正向IoC容器获取被管理Bean的过程  
9        return doGetBean(name, requiredType, null, false);  
10    }  
11    //获取IoC容器中指定名称和参数的Bean  
12    public Object getBean(String name, Object... args) throws BeansException {  
13        //doGetBean才是真正向IoC容器获取被管理Bean的过程  
14        return doGetBean(name, null, args, false);  
15    }  
16    //获取IoC容器中指定名称、类型和参数的Bean  
17    public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {  
18    //doGetBean才是真正向IoC容器获取被管理Bean的过程  
19        return doGetBean(name, requiredType, args, false);  
20    }  
21    //真正实现向IoC容器获取Bean的功能,也是触发依赖注入功能的地方  
22    @SuppressWarnings("unchecked")  
23    protected <T> T doGetBean(  
24            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)  
25            throws BeansException {  
26        //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖  
27        //如果指定的是别名,将别名转换为规范的Bean名称  
28        final String beanName = transformedBeanName(name);  
29        Object bean;  
30        //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单态模式的Bean整  
31        //个IoC容器中只创建一次,不需要重复创建  
32        Object sharedInstance = getSingleton(beanName);  
33        //IoC容器创建单态模式Bean实例对象  
34        if (sharedInstance != null && args == null) {  
35            if (logger.isDebugEnabled()) {  
36                //如果指定名称的Bean在容器中已有单态模式的Bean被创建,直接返回  
37                //已经创建的Bean  
38                if (isSingletonCurrentlyInCreation(beanName)) {  
39                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +  
40                            "' that is not fully initialized yet - a consequence of a circular reference");  
41                }  
42                else {  
43                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");  
44                }  
45            }  
46            //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理  
47            //注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是  
48            //创建创建对象的工厂Bean,两者之间有区别  
49            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
50        }  
51        else {//缓存没有正在创建的单态模式Bean  
52            //缓存中已经有已经创建的原型模式Bean,但是由于循环引用的问题导致实  
53            //例化对象失败  
54            if (isPrototypeCurrentlyInCreation(beanName)) {  
55                throw new BeanCurrentlyInCreationException(beanName);  
56            }  
57            //对IoC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否  
58            //能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器  
59            //的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找  
60            BeanFactory parentBeanFactory = getParentBeanFactory();  
61            //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean  
62            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
63                //解析指定Bean名称的原始名称  
64                String nameToLookup = originalBeanName(name);  
65                if (args != null) {  
66                    //委派父级容器根据指定名称和显式的参数查找  
67                    return (T) parentBeanFactory.getBean(nameToLookup, args);  
68                }  
69                else {  
70                    //委派父级容器根据指定名称和类型查找  
71                    return parentBeanFactory.getBean(nameToLookup, requiredType);  
72                }  
73            }  
74            //创建的Bean是否需要进行类型验证,一般不需要  
75            if (!typeCheckOnly) {  
76                //向容器标记指定的Bean已经被创建  
77                markBeanAsCreated(beanName);  
78            }  
79             //根据指定Bean名称获取其父级的Bean定义,主要解决Bean继承时子类  
80            //合并父类公共属性问题  
81            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
82            checkMergedBeanDefinition(mbd, beanName, args);  
83            //获取当前Bean所有依赖Bean的名称  
84            String[] dependsOn = mbd.getDependsOn();  
85            //如果当前Bean有依赖Bean  
86            if (dependsOn != null) {  
87                for (String dependsOnBean : dependsOn) {  
88                    //递归调用getBean方法,获取当前Bean的依赖Bean  
89                    getBean(dependsOnBean);  
90                    //把被依赖Bean注册给当前依赖的Bean  
91                    registerDependentBean(dependsOnBean, beanName);  
92                }  
93            }  
94            //创建单态模式Bean的实例对象  
95            if (mbd.isSingleton()) {  
96            //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象  
97                sharedInstance = getSingleton(beanName, new ObjectFactory() {  
98                    public Object getObject() throws BeansException {  
99                        try {  
100                            //创建一个指定Bean实例对象,如果有父级继承,则合并子//类和父类的定义  
101                            return createBean(beanName, mbd, args);  
102                        }  
103                        catch (BeansException ex) {  
104                            //显式地从容器单态模式Bean缓存中清除实例对象  
105                            destroySingleton(beanName);  
106                            throw ex;  
107                        }  
108                    }  
109                });  
110                //获取给定Bean的实例对象  
111                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
112            }  
113            //IoC容器创建原型模式Bean实例对象  
114            else if (mbd.isPrototype()) {  
115                //原型模式(Prototype)是每次都会创建一个新的对象  
116                Object prototypeInstance = null;  
117                try {  
118                    //回调beforePrototypeCreation方法,默认的功能是注册当前创//建的原型对象  
119                    beforePrototypeCreation(beanName);  
120                    //创建指定Bean对象实例  
121                    prototypeInstance = createBean(beanName, mbd, args);  
122                }  
123                finally {  
124                    //回调afterPrototypeCreation方法,默认的功能告诉IoC容器指//定Bean的原型对象不再创建了  
125                    afterPrototypeCreation(beanName);  
126                }  
127                //获取给定Bean的实例对象  
128                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
129            }  
130            //要创建的Bean既不是单态模式,也不是原型模式,则根据Bean定义资源中  
131            //配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中  
132            //比较常用,如:request、session、application等生命周期  
133            else {  
134                String scopeName = mbd.getScope();  
135                final Scope scope = this.scopes.get(scopeName);  
136                //Bean定义资源中没有配置生命周期范围,则Bean定义不合法  
137                if (scope == null) {  
138                    throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");  
139                }  
140                try {  
141                    //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例  
142                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {  
143                        public Object getObject() throws BeansException {  
144                            beforePrototypeCreation(beanName);  
145                            try {  
146                                return createBean(beanName, mbd, args);  
147                            }  
148                            finally {  
149                                afterPrototypeCreation(beanName);  
150                            }  
151                        }  
152                    });  
153                    //获取给定Bean的实例对象  
154                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);  
155                }  
156                catch (IllegalStateException ex) {  
157                    throw new BeanCreationException(beanName,  
158                            "Scope '" + scopeName + "' is not active for the current thread; " +  
159                            "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",  
160                            ex);  
161                }  
162            }  
163        }  
164        //对创建的Bean实例对象进行类型检查  
165        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {  
166            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());  
167        }  
168        return (T) bean;  
169    } 

 

通过上面对向IoC容器获取Bean方法的分析,我们可以看到在Spring中,如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean定义还可以扩展为指定其生命周期范围。

上面的源码只是定义了根据Bean定义的模式,采取的不同创建Bean实例对象的策略,具体的Bean实例对象的创建过程由实现了ObejctFactory接口的匿名内部类的createBean方法完成,ObejctFactory使用委派模式,具体的Bean实例创建过程交由其实现类AbstractAutowireCapableBeanFactory完成,我们继续分析AbstractAutowireCapableBeanFactory的createBean方法的源码,理解其创建Bean实例的具体实现过程。

依赖注入的过程:

1.获取IOC容器的指定的bean

  • 根据指定的名称获取被管理的Bean名称 剥离指定名称对容器的相关依赖 如果是别名 将别名转化为规范Bean名称
  • 从缓存中获取已经被创建的单例bean 如果缓存中已存在单例bean 则直接返回已创建的单例bean 如果没有 则创建 转下
  • 获取当前bean所依赖的bean 把被依赖的bean注册给当前bean
  • 配置生命周期范围 选择实例化bean的方法 singleton prototype request session global-session
  • 创建bean 转2
  • 对创建的bean进行检查

2.创建bean的实例化对象

  • 检查bean是可实例化的
  • 根据条件判断实例化方法 工厂实例化 自动装配实例化 默认无参构造函数实例化

3.在实例化过程中对匿名内置类 根据实例化策略实例化

通过对上面注入依赖代码的分析,我们已经明白了Spring IoC容器是如何将属性的值注入到Bean实例对象中去的:

(1).对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性。

(2).对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的getter方法(reader method)获取指定属性注入以前的值,同时调用属性的setter方法(writer method)为属性设置注入后的值。看到这里相信很多人都明白了Spring的setter注入原理。

至此Spring IoC容器对Bean定义资源文件的定位,载入、解析和依赖注入已经全部分析完毕,现在Spring IoC容器中管理了一系列靠依赖关系联系起来的Bean,程序不需要应用自己手动创建所需的对象,Spring IoC容器会在我们使用的时候自动为我们创建,并且为我们注入好相关的依赖,这就是Spring核心功能的控制反转和依赖注入的相关功能。

 

IoC容器的高级特性

   通过对Spring IoC容器的源码分析,我们已经基本上了解了Spring IoC容器对Bean定义资源的定位、读入和解析过程,同时也清楚了当用户通过getBean方法向IoC容器获取被管理的Bean时,IoC容器对Bean进行的初始化和依赖注入过程,这些是Spring IoC容器的基本功能特性。Spring IoC容器还有一些高级特性,如使用lazy-init属性对Bean预初始化FactoryBean产生或者修饰Bean对象的生成IoC容器初始化Bean过程中使用BeanPostProcessor后置处理器对Bean声明周期事件管理IoC容器的autowiring自动装配功能等。

1.Spring IoC容器的lazy-init属性实现预实例化:

   通过前面我们对IoC容器的实现和工作原理分析,我们知道IoC容器的初始化过程就是对Bean定义资源的定位、载入和注册,此时容器对Bean的依赖注入并没有发生,依赖注入主要是在应用程序第一次向容器索取Bean时,通过getBean方法的调用完成。

当Bean定义资源的<Bean>元素中配置了lazy-init属性时,容器将会在初始化的时候对所配置的Bean进行预实例化,Bean的依赖注入在容器初始化的时候就已经完成。这样,当应用程序第一次向容器索取被管理的Bean时,就不用再初始化和对Bean进行依赖注入了,直接从容器中获取已经完成依赖注入的现成Bean,可以提高应用第一次向容器获取Bean的性能。

我们知道IoC容器读入已经定位的Bean定义资源是从refresh方法开始的,我们首先从AbstractApplicationContext类的refresh方法入手分析。在refresh方法中ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory();启动了Bean定义资源的载入、注册过程,而finishBeanFactoryInitialization方法是对注册后的Bean定义中的预实例化(默认lazy-init=false,预实例化为true)的Bean进行处理的地方。

 

finishBeanFactoryInitialization处理预实例化Bean:

当Bean定义资源被载入IoC容器之后,容器将Bean定义资源解析为容器内部的数据结构BeanDefinition注册到容器中,AbstractApplicationContext类中的finishBeanFactoryInitialization方法对配置了预实例化属性的Bean进行预初始化过程,源码如下:

//对配置了lazy-init属性的Bean进行预实例化处理  
2    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {  
3        //这是Spring3以后新加的代码,为容器指定一个转换服务(ConversionService)  
4        //在对某些Bean属性进行转换时使用  
5        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&  
6                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {  
7            beanFactory.setConversionService(  
8                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));  
9        }  
10        //为了类型匹配,停止使用临时的类加载器  
11        beanFactory.setTempClassLoader(null);  
12        //缓存容器中所有注册的BeanDefinition元数据,以防被修改  
13        beanFactory.freezeConfiguration();  
14        //对配置了lazy-init属性的单态模式Bean进行预实例化处理  
15        beanFactory.preInstantiateSingletons();  
    } 

ConfigurableListableBeanFactory是一个接口,其preInstantiateSingletons方法由其子类DefaultListableBeanFactory提供。  

DefaultListableBeanFactory对配置lazy-init属性单态Bean的预实例化:

//对配置lazy-init属性单态Bean的预实例化  
2public void preInstantiateSingletons() throws BeansException {  
3        if (this.logger.isInfoEnabled()) {  
4            this.logger.info("Pre-instantiating singletons in " + this);  
5        }  
6        //在对配置lazy-init属性单态Bean的预实例化过程中,必须多线程同步,以确保数据一致性  
7        synchronized (this.beanDefinitionMap) {  
8            for (String beanName : this.beanDefinitionNames) {  
9                //获取指定名称的Bean定义  
10                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);  
11                //Bean不是抽象的,是单态模式的,且lazy-init属性配置为false  
12                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {  
13                    //如果指定名称的bean是创建容器的Bean  
14                    if (isFactoryBean(beanName)) {  
15                    //FACTORY_BEAN_PREFIX=”&”,当Bean名称前面加”&”符号  
16                   //时,获取的是产生容器对象本身,而不是容器产生的Bean.  
17                   //调用getBean方法,触发容器对Bean实例化和依赖注入过程  
18                        final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);  
19                        //标识是否需要预实例化  
20                        boolean isEagerInit;  
21                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {  
22                            //一个匿名内部类  
23                            isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {  
24                                public Boolean run() {  
25                                    return ((SmartFactoryBean) factory).isEagerInit();  
26                                }  
27                            }, getAccessControlContext());  
28                        }  
29                        else {  
30                            isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();   
31                        }  
32                        if (isEagerInit) {  
33                           //调用getBean方法,触发容器对Bean实例化和依赖注入过程  
34                            getBean(beanName);  
35                        }  
36                    }  
37                    else {  
38                         //调用getBean方法,触发容器对Bean实例化和依赖注入过程  
39                        getBean(beanName);  
40                    }  
41                }  
42            }  
43        }  
    } 

通过对lazy-init处理源码的分析,我们可以看出,如果设置了lazy-init属性,则容器在完成Bean定义的注册之后,会通过getBean方法,触发对指定Bean的初始化和依赖注入过程,这样当应用第一次向容器索取所需的Bean时,容器不再需要对Bean进行初始化和依赖注入,直接从已经完成实例化和依赖注入的Bean中取一个线程的Bean,这样就提高了第一次获取Bean的性能。

3、FactoryBean的实现:

       在Spring中,有两个很容易混淆的类:BeanFactory和FactoryBean。

BeanFactory:Bean工厂,是一个工厂(Factory),我们Spring IoC容器的最顶层接口就是这个BeanFactory,它的作用是管理Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

FactoryBean:工厂Bean,是一个Bean,作用是产生其他bean实例。通常情况下,这种bean没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他bean实例。通常情况下,bean无须自己实现工厂模式,Spring容器担任工厂角色;但少数情况下,容器中的bean本身就是工厂,其作用是产生其它bean实例。

当用户使用容器本身时,可以使用转义字符”&”来得到FactoryBean本身,以区别通过FactoryBean产生的实例对象和FactoryBean对象本身。在BeanFactory中通过如下代码定义了该转义字符:

StringFACTORY_BEAN_PREFIX = "&";

如果myJndiObject是一个FactoryBean,则使用&myJndiObject得到的是myJndiObject对象,而不是myJndiObject产生出来的对象。

FactoryBean的源码如下:

//工厂Bean,用于产生其他对象  
public interface FactoryBean<T> {  
   //获取容器管理的对象实例  
    T getObject() throws Exception;  
    //获取Bean工厂创建的对象的类型  
    Class<?> getObjectType();  
    //Bean工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例  
   //对象,每次请求都返回同一个实例对象  
    boolean isSingleton();  
} 

AbstractBeanFactory的getBean方法调用FactoryBean:

在前面我们分析Spring Ioc容器实例化Bean并进行依赖注入过程的源码时,提到在getBean方法触发容器实例化Bean的时候会调用AbstractBeanFactory的doGetBean方法来进行实例化的过程,源码如下:

 

    //真正实现向IoC容器获取Bean的功能,也是触发依赖注入功能的地方    
2      @SuppressWarnings("unchecked")    
3      protected <T> T doGetBean(    
4              final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)    
5              throws BeansException {    
6          //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖    
7          //如果指定的是别名,将别名转换为规范的Bean名称    
8          final String beanName = transformedBeanName(name);    
9          Object bean;    
10        //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单态模式的Bean整    
11            //个IoC容器中只创建一次,不需要重复创建    
12          Object sharedInstance = getSingleton(beanName);    
13          //IoC容器创建单态模式Bean实例对象    
14          if (sharedInstance != null && args == null) {    
15              if (logger.isDebugEnabled()) {    
16              //如果指定名称的Bean在容器中已有单态模式的Bean被创建,直接返回    
17                    //已经创建的Bean    
18                  if (isSingletonCurrentlyInCreation(beanName)) {    
19                      logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +    
20                              "' that is not fully initialized yet - a consequence of a circular reference");    
21                  }    
22                  else {    
23                      logger.debug("Returning cached instance of singleton bean '" + beanName + "'");    
24                  }    
25              }    
26              //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理   
27              bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);    
28          }    
29         ……  
30     }  
31    //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理 
32    protected Object getObjectForBeanInstance(  
33            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {  
34        //容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,也可能是  
35        //一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,如果  
36        //调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象  
37        //如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),  
38        //且Bean实例也不是创建Bean实例对象的工厂Bean  
39        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {  
40            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());  
41        }  
42        //如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,调用者向获取对  
43        //容器的引用,则直接返回当前的Bean实例  
44        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {  
45            return beanInstance;  
46        }  
47    //处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean  
48    //使用工厂Bean创建一个Bean的实例对象  
49        Object object = null;  
50        if (mbd == null) {  
51            //从Bean工厂缓存中获取给定名称的Bean实例对象  
52            object = getCachedObjectForFactoryBean(beanName);  
53        }  
54        //让Bean工厂生产给定名称的Bean对象实例  
55        if (object == null) {  
56            FactoryBean factory = (FactoryBean) beanInstance;  
57            //如果从Bean工厂生产的Bean是单态模式的,则缓存  
58            if (mbd == null && containsBeanDefinition(beanName)) {  
59                //从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性  
60                mbd = getMergedLocalBeanDefinition(beanName);  
61            }  
62            //如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,则让工厂  
63            //Bean生产Bean实例对象  
64            boolean synthetic = (mbd != null && mbd.isSynthetic());  
65            //调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean  
66            //方法,实现工厂Bean生产Bean对象实例的过程  
67            object = getObjectFromFactoryBean(factory, beanName, !synthetic);  
68        }  
69        return object;  
    } 

在上面获取给定Bean的实例对象的getObjectForBeanInstance方法中,会调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,该方法实现了Bean工厂生产Bean实例对象。 

Dereference(解引用):一个在C/C++中应用比较多的术语,在C++中,”*”是解引用符号,而”&”是引用符号,解引用是指变量指向的是所引用对象的本身数据,而不是引用对象的内存地址。

 

3.BeanPostProcessor后置处理器的实现:

BeanPostProcessor后置处理器是Spring IoC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器向容器注册以后,容器中管理的Bean就具备了接收IoC容器事件回调的能力。

BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件中设置即可。

BeanPostProcessor的源码如下:

1    package org.springframework.beans.factory.config;  
2    import org.springframework.beans.BeansException;  
3    public interface BeanPostProcessor {  
4        //为在Bean的初始化前提供回调入口  
5        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
6        //为在Bean的初始化之后提供回调入口  
7        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
     }  

这两个回调的入口都是和容器管理的Bean的生命周期事件紧密相关,可以为用户提供在Spring IoC容器初始化Bean过程中自定义的处理操作。

AbstractAutowireCapableBeanFactory类对容器生成的Bean添加后置处理器:

BeanPostProcessor后置处理器的调用发生在Spring IoC容器完成对Bean实例对象的创建和属性的依赖注入完成之后,在对Spring依赖注入的源码分析过程中我们知道,当应用程序第一次调用getBean方法(lazy-init预实例化除外)向Spring IoC容器索取指定Bean时触发Spring IoC容器创建Bean实例对象并进行依赖注入的过程,其中真正实现创建Bean对象并进行依赖注入的方法是AbstractAutowireCapableBeanFactory类的doCreateBean方法,为Bean实例对象添加BeanPostProcessor后置处理器的入口的是initializeBean方法。

initializeBean方法为容器产生的Bean实例对象添加BeanPostProcessor后置处理器:

 同样在AbstractAutowireCapableBeanFactory类中,initializeBean方法实现为容器创建的Bean实例对象添加BeanPostProcessor后置处理器,源码如下:

 //初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器  
2    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {  
3        //JDK的安全机制验证权限  
4        if (System.getSecurityManager() != null) {  
5            //实现PrivilegedAction接口的匿名内部类  
6            AccessController.doPrivileged(new PrivilegedAction<Object>() {  
7                public Object run() {  
8                    invokeAwareMethods(beanName, bean);  
9                    return null;  
10                }  
11            }, getAccessControlContext());  
12        }  
13        else {  
14            //为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息  
15            invokeAwareMethods(beanName, bean);  
16        }  
17        Object wrappedBean = bean;  
18        //对BeanPostProcessor后置处理器的postProcessBeforeInitialization  
19        //回调方法的调用,为Bean实例初始化前做一些处理  
20        if (mbd == null || !mbd.isSynthetic()) {  
21            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
22        }  
23        //调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置  
24        //文件中通过init-method属性指定的  
25        try {  
26            invokeInitMethods(beanName, wrappedBean, mbd);  
27        }  
28        catch (Throwable ex) {  
29            throw new BeanCreationException(  
30                    (mbd != null ? mbd.getResourceDescription() : null),  
31                    beanName, "Invocation of init method failed", ex);  
32        }  
33        //对BeanPostProcessor后置处理器的postProcessAfterInitialization  
34        //回调方法的调用,为Bean实例初始化之后做一些处理  
35        if (mbd == null || !mbd.isSynthetic()) {  
36            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
37        }  
38        return wrappedBean;  
39    }  
40    //调用BeanPostProcessor后置处理器实例对象初始化之前的处理方法  
41    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)  
42            throws BeansException {  
43        Object result = existingBean;  
44        //遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器  
45        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {  
46            //调用Bean实例所有的后置处理中的初始化前处理方法,为Bean实例对象在  
47            //初始化之前做一些自定义的处理操作  
48            result = beanProcessor.postProcessBeforeInitialization(result, beanName);  
49            if (result == null) {  
50                return result;  
51            }  
52        }  
53        return result;  
54    }  
55    //调用BeanPostProcessor后置处理器实例对象初始化之后的处理方法  
56    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)  
57            throws BeansException {  
58        Object result = existingBean;  
59        //遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器  
60        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {  
61            //调用Bean实例所有的后置处理中的初始化后处理方法,为Bean实例对象在  
62            //初始化之后做一些自定义的处理操作  
63            result = beanProcessor.postProcessAfterInitialization(result, beanName);  
64            if (result == null) {  
65                return result;  
66            }  
67        }  
68        return result;  
    } 

BeanPostProcessor是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring中,BeanPostProcessor的实现子类非常的多,分别完成不同的操作,如:AOP面向切面编程的注册通知适配器、Bean对象的数据校验、Bean继承属性/方法的合并等等,我们以最简单的AOP切面织入来简单了解其主要的功能。

AdvisorAdapterRegistrationManager在Bean对象初始化后注册通知适配器:

 AdvisorAdapterRegistrationManager是BeanPostProcessor的一个实现类,其主要的作用为容器中管理的Bean注册一个面向切面编程的通知适配器,以便在Spring容器为所管理的Bean进行面向切面编程时提供方便,其源码如下:

 

//为容器中管理的Bean注册一个面向切面编程的通知适配器  
2 public class AdvisorAdapterRegistrationManager implements BeanPostProcessor {  
3    //容器中负责管理切面通知适配器注册的对象  
4    private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();  
5    public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {  
6        this.advisorAdapterRegistry = advisorAdapterRegistry;  
7    }  
8    //BeanPostProcessor在Bean对象初始化前的操作  
9    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
10        //没有做任何操作,直接返回容器创建的Bean对象  
11        return bean;  
12    }  
13    //BeanPostProcessor在Bean对象初始化后的操作  
14    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
15        if (bean instanceof AdvisorAdapter){  
16            //如果容器创建的Bean实例对象是一个切面通知适配器,则向容器的注册
              this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);  
17        }  
18        return bean;  
19    }  
} 

 

其他的BeanPostProcessor接口实现类的也类似,都是对Bean对象使用到的一些特性进行处理,或者向IoC容器中注册,为创建的Bean实例对象做一些自定义的功能增加,这些操作是容器初始化Bean时自动触发的,不需要人为的干预。

 

4.Spring IoC容器autowiring实现原理:

Spring IoC容器提供了两种管理Bean依赖关系的方式:

  • 显式管理:通过BeanDefinition的属性值和构造方法实现Bean依赖关系管理。
  • autowiring:Spring IoC容器的依赖自动装配功能,不需要对Bean属性的依赖关系做显式的声明,只需要在配置好autowiring属性,IoC容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的Bean,从而自动地完成依赖注入。

 

通过对autowiring自动装配特性的理解,我们知道容器对Bean的自动装配发生在容器对Bean依赖注入的过程中。在前面对Spring IoC容器的依赖注入过程源码分析中,我们已经知道了容器对Bean实例对象的属性注入的处理发生在AbstractAutoWireCapableBeanFactory类中的populateBean方法中,我们通过程序流程分析autowiring的实现原理:

 

AbstractAutoWireCapableBeanFactory对Bean实例进行属性依赖注入:

 应用第一次通过getBean方法(配置了lazy-init预实例化属性的除外)向IoC容器索取Bean时,容器创建Bean实例对象,并且对Bean实例对象进行属性依赖注入,AbstractAutoWireCapableBeanFactory的populateBean方法就是实现Bean属性依赖注入的功能,其主要源码如下:

 protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {  
2        //获取Bean定义的属性值,并对属性值进行处理  
3        PropertyValues pvs = mbd.getPropertyValues();  
4        ……  
5        //对依赖注入处理,首先处理autowiring自动装配的依赖注入  
6        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
7                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
8            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
9            //根据Bean名称进行autowiring自动装配处理  
10            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
11                autowireByName(beanName, mbd, bw, newPvs);  
12            }  
13            //根据Bean类型进行autowiring自动装配处理  
14            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
15                autowireByType(beanName, mbd, bw, newPvs);  
16            }  
17        }  
18        //对非autowiring的属性进行依赖注入处理  
19         ……  
    } 

 

Spring IoC容器根据Bean名称或者类型进行autowiring自动依赖注入:

 //根据名称对属性进行自动依赖注入  
2    protected void autowireByName(  
3            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {  
4         //对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符串,URL等//都是简单属性)进行处理  
5        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
6        for (String propertyName : propertyNames) {  
7            //如果Spring IoC容器中包含指定名称的Bean  
8            if (containsBean(propertyName)) {  
9                 //调用getBean方法向IoC容器索取指定名称的Bean实例,迭代触发属性的//初始化和依赖注入  
10                Object bean = getBean(propertyName);  
11                //为指定名称的属性赋予属性值  
12                pvs.add(propertyName, bean);  
13                //指定名称属性注册依赖Bean名称,进行属性依赖注入  
14                registerDependentBean(propertyName, beanName);  
15                if (logger.isDebugEnabled()) {  
16                    logger.debug("Added autowiring by name from bean name '" + beanName +  
17                            "' via property '" + propertyName + "' to bean named '" + propertyName + "'");  
18                }  
19            }  
20            else {  
21                if (logger.isTraceEnabled()) {  
22                    logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +  
23                            "' by name: no matching bean found");  
24                }  
25            }  
26        }  
27    }  
28    //根据类型对属性进行自动依赖注入  
29    protected void autowireByType(  
30            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {  
31        //获取用户定义的类型转换器  
32        TypeConverter converter = getCustomTypeConverter();  
33        if (converter == null) {  
34            converter = bw;  
35        }  
36        //存放解析的要注入的属性  
37        Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);  
38          //对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符  
39         //URL等都是简单属性)进行处理  
40        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
41        for (String propertyName : propertyNames) {  
42            try {  
43                //获取指定属性名称的属性描述器  
44                PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);  
45                //不对Object类型的属性进行autowiring自动依赖注入  
46                if (!Object.class.equals(pd.getPropertyType())) {  
47                    //获取属性的setter方法  
48                    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);  
49                    //检查指定类型是否可以被转换为目标对象的类型  
50                    boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());  
51                    //创建一个要被注入的依赖描述  
52                    DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);  
53                    //根据容器的Bean定义解析依赖关系,返回所有要被注入的Bean对象  
54                    Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);  
55                    if (autowiredArgument != null) {  
56                        //为属性赋值所引用的对象  
57                        pvs.add(propertyName, autowiredArgument);  
58                    }  
59                    for (String autowiredBeanName : autowiredBeanNames) {  
60                        //指定名称属性注册依赖Bean名称,进行属性依赖注入  
61                        registerDependentBean(autowiredBeanName, beanName);  
62                        if (logger.isDebugEnabled()) {  
63                            logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +  
64                                    propertyName + "' to bean named '" + autowiredBeanName + "'");  
65                        }  
66                    }  
67                    //释放已自动注入的属性  
68                    autowiredBeanNames.clear();  
69                }  
70            }  
71            catch (BeansException ex) {  
72                throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);  
73            }  
74        }  
    } 

通过上面的源码分析,我们可以看出来通过属性名进行自动依赖注入的相对比通过属性类型进行自动依赖注入要稍微简单一些,但是真正实现属性注入的是DefaultSingletonBeanRegistry类的registerDependentBean方法。

DefaultSingletonBeanRegistry的registerDependentBean方法对属性注入:

 

 //为指定的Bean注入依赖的Bean  
2    public void registerDependentBean(String beanName, String dependentBeanName) {  
3        //处理Bean名称,将别名转换为规范的Bean名称  
4        String canonicalName = canonicalName(beanName);  
5        //多线程同步,保证容器内数据的一致性  
6        //先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Bean  
7        synchronized (this.dependentBeanMap) {  
8            //获取给定名称Bean的所有依赖Bean名称  
9            Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);  
10            if (dependentBeans == null) {  
11                //为Bean设置依赖Bean信息  
12                dependentBeans = new LinkedHashSet<String>(8);  
13                this.dependentBeanMap.put(canonicalName, dependentBeans);  
14            }  
15            //向容器中:bean名称-->全部依赖Bean名称集合添加Bean的依赖信息  
16            //即,将Bean所依赖的Bean添加到容器的集合中  
17            dependentBeans.add(dependentBeanName);  
18        }  
19          //从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称  
20         //Bean的依赖Bean  
21        synchronized (this.dependenciesForBeanMap) {  
22            Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);  
23            if (dependenciesForBean == null) {  
24                dependenciesForBean = new LinkedHashSet<String>(8);  
25                this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);  
26            }  
27            //向容器中:bean名称-->指定Bean的依赖Bean名称集合添加Bean的依赖信息  
28            //即,将Bean所依赖的Bean添加到容器的集合中  
29            dependenciesForBean.add(canonicalName);  
30        }  
    }

通过对autowiring的源码分析,我们可以看出,autowiring的实现过程:

a.    对Bean的属性迭代调用getBean方法,完成依赖Bean的初始化和依赖注入。

b.    将依赖Bean的属性引用设置到被依赖的Bean属性上。

c.     将依赖Bean的名称和被依赖Bean的名称存储在IoC容器的集合中。

 

Spring IoC容器的autowiring属性自动依赖注入是一个很方便的特性,可以简化开发时的配置,但是凡是都有两面性,自动属性依赖注入也有不足,首先,Bean的依赖关系在配置文件中无法很清楚地看出来,对于维护造成一定困难。其次,由于自动依赖注入是Spring容器自动执行的,容器是不会智能判断的,如果配置不当,将会带来无法预料的后果,所以自动依赖注入特性在使用时还是综合考虑。

Bean的生命周期

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值