×
广告

Spring IOC 实现原理

96
起个名忒难
2018.05.17 23:08 字数 4749

Spring IOC 实现原理

IOC: Inversion of Control ,即 "控制反转" , 不是什么技术,而是一种思想。原先需要自行实例化的对象, 交给IOC容器去实现。那么控制反转,谁被控制? 谁被反转 ?

在传统的JavaSE程序中,直接在类的内部通过new关键字来创建对象的实例,是程序主动去创建依赖对象,而IOC有一个专门的容器,来创建这些对象,由IOC容器来控制对象的创建,依赖对象也是容器帮忙查找创建并进行注入,对象只是被动的接受,依赖对象的获取被反转了。它还有一个更加形象的名字叫 依赖注入。

注入方式:

  • 接口注入
  • setter
  • 构造器注入

IOC容器的设计与实现有两种:BeanFactory和ApplicationContext

IOC容器的两个容器设计系列:

  • 实现了BeanFactory接口的简单容器系列,只是实现了容器最基本的功能
  • Applic ationContext应用上下文,作为容器的高级形态存在。除了具有基本的功能外,还增加了许多面向框架的特性,同时对应用环境做了许多适配。

BeanFactory

BeanFactory为IOC容器具体实现指定了基本的规范,换句话说BeanFactory是最顶层的类,它有三个子类,ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory接口。但是它们最终生成了一个默认的实现类DefaultListableBeanFactory。类的继承关系如下:


BeanFactory继承关系图.png

上图中DefaultListableBeanFactory的继承关系并不完整,删除了AliasRegistry接口的相关信息。

下面看一下BeanFactory接口中关于方法的定义:

public interface BeanFactory {
    //通过使用转义符“&”,来区分BeanFactory产生的对象和BeanFactory本身
    String FACTORY_BEAN_PREFIX = "&";
    //根据Bean的名字获取Bean的实例
    Object getBean(String var1) throws BeansException;
    //根据Bean的名字和Class类型来获取实例,增加了类型安全验证
    <T> T getBean(String var1, Class<T> var2) throws BeansException;
    //根据Class类型来获取实例
    <T> T getBean(Class<T> var1) throws BeansException;
    //返回实例
    Object getBean(String var1, Object... var2) throws BeansException;
    //是否包含指定的实例
    boolean containsBean(String var1);
    //是否单例
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    //是否是原型
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    //类型是否匹配
    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    //返回指定实例名的类型
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    //返回别名
    String[] getAliases(String var1);
}

通过对上面方法的分析,可以得出。BeanFactory并不关心bean是如何定义,怎样被加载的,当我们需要bean的时候,直接来取就可以了。对于工厂来说,我只需要关心有没有产品,对于产品是怎么产生,怎么制作的,那是工人干的事,工厂并不关心。定义的都是最核心的接口,如getBean(),从容器中获取实例。

ApplicationContext

ApplicationContext是Spring提供的一个高级的IOC容器,除了提供基本IOC容器的功能外,还能为用户提供:

  • 支持信息源,可以实现国际化
  • 访问资源
  • 支持应用事件
  • ApplicationContext中提供的附加服务

看一下ApplicationContext的继承关系。

AppliciationContext继承关系图.png

通过对上图的分析,可以看出ApplicationContext除了BeanFactory的功能,还具有ResourceLoader接口的功能,具有了高级容器特性的支持。

下面对接口的继承关系做一个简要的分析:

  • 在BeanFactory中,从BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一个条主要的设计路径。 BeanFactory中定义了基本的IOC容器规范,在HierarchicalBeanFactory接口中增加了getparantBeanFactory()的接口功能,使BeanFactory具备了双亲IOC容器的管理功能,在ConfigurableBeanFactory主要定义了一些对BeanFactory的配置功能
  • 在ApplicationContext中,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到常用的WebApplicationContext或者ConfigurableApplicationContext接口。在BeanFactory简单接口的基础上增加了对高级容器的特性支持。

BeanDefinition
SpringIOC容器帮我们管理了各种bean对象及其相互依赖的关系,Bean对象在Spring实现中是以BeanDefinition来描述的。*换句话说 依赖关系是使用BeanDefinition来保存的。 *其继承体系如下:

BeanDefinition继承关系图.png

Spring关于Bean的装配,有下面三种方式:

  • 在XML中进行显示配置
  • 在java中进行显示配置
  • 隐式的bean发现机制和自动装配

Bean的解析非常的复杂,功能被分的很细,需要扩展的地方也很多,必须保证有足够的灵活性,下面看一下基于xml配置文件解析的继承体系:

XmlBeanDefinitionReader的继承关系图.png

IOC容器的初始化

IOC容器的初始化包括:BeanDefinition的Resouce定位,BeanDefinition的载入和注册三个基本的过程。需要注意的是Spring把上面过程进行了分离,并使用了不同的模块来完成,定位使用了ResourceLoader,解析使用了BeanDefinitionReader等。这样设计的目的可以让用户对这三个过程进行裁剪和扩展,定义出适合自己的IOC容器初始化过程。

下面来看一下两种IOC容器的创建过程,BeanFactory以XmlBeanFactory为例,ApplicationContext 以 FileSystemXmlApplicationContext为例

XmlBeanFactroy

看一下XmlBeanFactory的源码定义:

public class XmlBeanFactory extends DefaultListableBeanFactory {
    //定义一个BeanDefinitionReader阅读器
    private final XmlBeanDefinitionReader reader;
    //构造方法,需要传入Resource,资源的定位
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }
    //构造方法重载,需要传入Resource,和父容器,此方法完成了读取器的初始化操作
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        this.reader.loadBeanDefinitions(resource);
    }
}

通过阅读XmlBeanFactory的源码可以看出。

XmlBeanFactory继承自DefaultListableBeanFactory类。而DefaultListableBeanFactory类包含了基本IOC容器所具有的重要功能。

那BeanDefinition的信息来源自哪,如何定位? 定位之后又如何读取解析呢??

对于信息来源的定位封装成Spring中的Resource类来给出,解析是它的内部定义了一个XmlBeanDefinitionReader对象,有了这个对象,就有了处理xml文件的能力。

参考XmlBeanFactory的实现,我们手动来模拟一下XmlBeanFactory的实现过程

//首先进行BeanDefinition资源文件的定位,封装为Source的子类
ClassPathResource res = new ClassPathResource("beans.xml");
//创建基本的IOC容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建文件读取器,并进行回调设置。
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//资源加载解析
reader.loadBeanDefinitions(res);

通过上面的代码,总结一下IOC容器的使用步骤:

  • 创建IOC抽象资源,这个抽象资源包含了BeanDefinition的定义信息
  • 创建一个BeanFactory
  • 创建一个BeanDefinition的读取器,通过一个回调配置给BeanFactory
  • 从定义好的抽象资源中读取配置信息。完成载入和注册的定义后,IOC容器就建立了起来了。

FileSystemXmlApplicationContext

先来看一下FileSystemXmlApplicationContext的继承关系:

image.png

通过上面的继承关系,可以发现它的基类AbstractXmlApplicationContext中已经实现了主要的功能。

在看一下这个类的源码实现,关于构造方法部分,我做了删减:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

    //构造方法重载,省略其他的构造方法
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if(refresh) {
            this.refresh();
        }
    }
    //通过一个FileSystemResource来得到一个在文件系统中定位的BeanDefinition
    protected Resource getResourceByPath(String path) {
        if(path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
}

除了构造方法和getResourceByPath外,并没有其他的方法。也就说它只是实现了和它自身设计相关的两个功能。

看一下该类的调用方式:

ApplicationContext context =new FileSystemXmlApplicationContext(xmlPath);

上面调用了参数是字符串的构造函数,但是,对构造函数的调用最终都会转到下面的方法来执行,refresh方法启动了整个容器的初始化流程:

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
      super(parent);
      this.setConfigLocations(configLocations);
      if(refresh) {
            this.refresh();
     }
}

来看一下上面的构造方法中,最终都执行了那些操作,具体的操作都是由那些类执行的。
通过代码跟随,可以发现,super(parent)这个方法最终是由其基类(AbstractApplicationContext)来执行,执行了AbstractApplicationContext的无参构造方法和setParent()方法。其代码如下,省略了静态代码块的定义:

//FileSystemXmlApplicationContext调用父类构造方法就是该方法
public AbstractApplicationContext(ApplicationContext parent) {
    this();
    setParent(parent);
}
//具体需要执行的方法
public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
}
//获取一个Source的加载器用于读入Spring Bean 定义资源文件
protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);
}
//设置双亲ioc容器
public void setParent(ApplicationContext parent) {
    this.parent = parent;
    if (parent != null) {
        Environment parentEnvironment = parent.getEnvironment();
        if (parentEnvironment instanceof ConfigurableEnvironment) {
            getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
        }
    }
}

调用父类的构造方法执行完成后,返回FileSystemXmlApplicationContext类,执行setConfigLocations(configLocations)方法,该方法的定义在类AbstractRefreshableConfigApplicationContext中:

//处理资源定义的数组,解析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++) {
                //解析路径
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

在资源定位的时候,支持下面两种方式:

  • ClasspathResource res = new ClasspathResource("a.xml,b.xml");
  • ClasspathResource res = new ClasspathResource("new String(){'a.xml' , 'b.xml'}")

具体实现的方式不在展开,感兴趣的可以去看一下源码实现

我们来看以上,程序执行到此处后,都做了哪些操作:

  1. 在AbstractApplicationContext中初始化了resourcePatternResolver(多资源文件的载入),用于获取Resource,关于何时使用后面再解释
  2. 将资源的定义路径保存在了configLocations数组中

到此,IOC容器根据资源定义路径获取Resouce的准备工作便完成了。

IOC容器的初始化过程

在开始分析初始化过程之前,先从宏观上对初始化的过程做一个简单的介绍,有一个大体框架的初始化模型,方便后面的理解,初始化过程分成了三个过程:

  • Resource定位
  • BeanDefinition的载入
  • 向IOC容器注册这些BeanDefinition信息。这个过程是通过BeanDefinitionRegistry接口的实现来完成的。最终注入到HashMap中去,这个hashmap就是持有beandefinition数据的。

下面来看一下FileSystemXmlApplicationContext中的关于refresh()方法的调用,实际调用的是AbstractApplicationContext中的refresh()方法,该方法定义如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //环境准备,获取容器启动的时间,设置活动标志,以及属性的初始化
        prepareRefresh();
        //在子类中启动resreshBeanfactory()方法
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //为BeanFactory配置容器属性
        prepareBeanFactory(beanFactory);
        try {
            //设置BeanFactory的后置处理
            postProcessBeanFactory(beanFactory);
            //调用后置处理,为这些后置处理器在Bean的定义中向容器注册
            invokeBeanFactoryPostProcessors(beanFactory);
            //注册Bean的后续处理,在Bean创建过程中调用
            registerBeanPostProcessors(beanFactory);
            //初始化上下文消息机制
            initMessageSource();
            //初始化上下文中事件机制
            initApplicationEventMulticaster();
            //初始化其他特殊的Bean
            onRefresh();
            //检查监听Bean并且将这些Bean向容器注册
            registerListeners();
            //初始化所有的singleton beans , 设置lazy-init = true 的bean除外
            finishBeanFactoryInitialization(beanFactory);
            //发布容器事件,结束Refresh过程
            finishRefresh();
        }catch (BeansException ex) {
            // 为防止Bean资源占用,在异常处理中,销毁已经生成的单件Bean
            destroyBeans();
            //重置Rest标志
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
    }
}

refresh()方法主要为IOC容器Bean的生命周期提供管理条件。Spring IOC容器的生成是从refreshBeanFactory()方法开始的,也就是执行了下面的代码:

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //使用委派模式,父类只是定义了方法,具体实现交给子类
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

在AbstractApplicationContext抽象类中,只是进行了refreshBeanFactory()方法的定义,方法的实现是在其子类AbstractRefreshableApplicationContext中实现的,在子类的定义如下:

protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) { //如果已经有容器,则销毁并关闭容器
        destroyBeans();
        closeBeanFactory();
    }
    try {
        //创建IOC容器
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        //对容器进行定制化,如设置启动参数,开启注解自动装配等
        customizeBeanFactory(beanFactory);
        //委派模式,资源的加载交给子类实现,启动对BeanDefinition的载入操作
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

上面代码loadBeanDefinitions(beanFactory);我们说是一个委派模式,只是进行了方法的定义,具体实现则是由AbstractXmlApplicationContext类实现,在该方法中创建了读取器XmlBeanDefinitionReader的实例,然后把这个读取器在IOC容器中设置好,最后是启动读取器来完成对BeanDefinition在IOC容器中的载入,定义如下:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    //创建XmlBeanDefinitionReader
    //即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器,读取Bean定义资源
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    //为Bean读取器设置资源加载器
    beanDefinitionReader.setResourceLoader(this);
    //设置一个Sax实体用于解析
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    //当Bean读取器读取Bean定义的xml资源文件时,启用xml校验机制
    initBeanDefinitionReader(beanDefinitionReader);
    //Bean 读取器真正的实现加载的方法
    loadBeanDefinitions(beanDefinitionReader);
}

在XmlBeanDefinitionReader的初始化过程中,还进行了一些其他的操作,具体如下:

//调用父类的构造方法
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    super(registry);
}
//父类构造方法
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    //赋值
    this.registry = registry;
    //判断register是否是ResourceLoader 类型
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        //为resourceLoader 新建一个资源加载器
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }
    //判断register 是否是 EnvironmentCapable类型
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {
        //初始化一个environment 
        this.environment = new StandardEnvironment();
    }
}

通过上面代码发现,在创建XmlBeanDefinitionReader的过程中,完成了resourceLoader和eviironment的赋值操作。

首先得到BeanDefinition信息的Resource定位,然后直接调用XmlBeanDefinitionReader来读取,具体的载入过程是委托给BeanDefinitionReader来完成的。因为使用的FileSystemXmlApplicationContext, getConfigResources()方法返回的是null,所以程序会走第二个分支

 //Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    //获取资源定位
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位 
        reader.loadBeanDefinitions(configResources);
    }
    //如果子类获取的Bean定义为空,则获取FileSystemXmlApplication构造方法中setConfigLocations方法设置的资源。
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinition(configLocations);
    }
}

程序分析到这,来梳理一下上面的执行流程。

  • 在FileSystemXmlApplicationContext一共做了三件事

    • 调用了父类的构造器,进行了初始化
    • 设置了BeanDefinition的定义路径
    • 执行了Refresh()方法
  • refresh()方法来启动整个BeanDefinition的载入过程

    • 创建容器 DefaultListableBeanFactory
    • 创建了XmlXmlBeanDefinitionReader
    • 开始准备通过reader来加载资源

AbstractBeanDefinitionReader读取Bean定义资源,AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:

//方法重载
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    String[] var3 = locations;
    int var4 = locations.length;
    for(int var5 = 0; var5 < var4; ++var5) {
        String location = var3[var5];
        counter += this.loadBeanDefinitions(location);
    }
    return counter;
}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(location, (Set)null);
}
//重载的最终执行方法
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    //获取资源加载器
    //上面提到过,XmlBeanDefinitionReader初始化时,在其父类中执行了加载器的初始化操作
    //resourceLoader的类型为PathMatchingResourcePatternResolver
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }
    //判断类型
    if (resourceLoader instanceof ResourcePatternResolver) {
        try {
            //将指定位置的Bean定义资源文件解析转化为Resource
            //加载多个指定位置的资源定义文件
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            //读取Resource
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
            }
            return loadCount;
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    }
    else {
        // Can only load single resources by absolute URL.
        Resource resource = resourceLoader.getResource(location);
        int loadCount = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
        }
        return loadCount;
    }
}

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Resource resource = var3[var5];
            counter += this.loadBeanDefinitions((Resource)resource);
        }

        return counter;
    }

上面的方法主要进行了两件事:

  • 调用资源加载器获取资源 resourceLoader.getResource(location)
  • 真正执行加载功能的是子类XmlBeanDefinitionReader的loadBeanDefinitions方法

loadBeanDefinitions()方法在AbstractBeanDefinitionReader中并没有具体的实现,它会转到XmlBeanDefinitionReader中的loadBeanDefinitions(Resource resource)中运行:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    //对xml资源进行编码处理
    return this.loadBeanDefinitions(new EncodedResource(resource));
}
//方法重载,转入此方法执行
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if(this.logger.isInfoEnabled()) {
        this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }
    Object currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
    if(currentResources == null) {
        currentResources = new HashSet(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if(!((Set)currentResources).add(encodedResource)) {
        throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    } else {
        int var5;
        try {
            //将资源文件转换为类型为InputStream的I/O流
            InputStream ex = encodedResource.getResource().getInputStream();
            try {
                //从InputStream中得到xML的解析源
                InputSource inputSource = new InputSource(ex);
                //编码如果不为null, 则设置inputSource的编码
                if(encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //读取数据
                var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            } finally {
                ex.close();
            }
        } catch (IOException var15) {
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
        } finally {
            ((Set)currentResources).remove(encodedResource);
            if(((Set)currentResources).isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
        return var5;
    }
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {
        try {
            //转化为Document 对象
            Document doc = doLoadDocument(inputSource, resource);
            //启动对Bean定义解析的详细过程,会用到Spring Bean的配置规则
            return registerBeanDefinitions(doc, resource);
        }
        //删除了部分catch语句
        catch (....) {
            throw ex;
        }
    }

将XML文件转换成Document对象,解析过程由documentLoader实现,getValidationModeForResource(resource)验证xml文件的模式 DTD还是XSD,此方法不在展开。

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource,getEntityResolver(), this.errorHandler,getValidationModeForResource(resource),isNamespaceAware());
    }

创建Document 的过程:

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    //创建文件解析工厂
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isDebugEnabled()) {
        logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
    }
    //创建文档解析器
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    //解析Spring bean定义资源 ,并返回Document对象
    return builder.parse(inputSource);
}

spring并没有对XML进行特殊的处理,使用了SAX对xml文档进行解析,操作分为三步:

  • 创建DocumentBuilderFactory
  • 创建DocumentBuilder
  • 解析inputSource对象,返回Document 对象

Document对象代表了一个XML文档的模型树,所有的其他Node都以一定的顺序包含在Document对象之内,排列成一个树状结构,以后对XML文档的所有操作都与解析器无关,直接在这个对象上操作即可。NodeList代表了包含一个或者多个Node的列表,操作上可以看作数组,使用getLength()获得列表中的节点数,item(int index ) 返回集合中第index个项。Node对象很少使用,会使用它的自对象Element,Attr 等。

至此,Spring IOC容器根据定位的Bean定义资源文件,并将其加载读入转换为document对象的过程完成。

上面略微呢有一点跑题,document对象的创建过程可能不是我们最关心的,我们关心就是Spring的BeanDefinition是怎样按照Spring的Bean语义要求进行解析并转化为容器内部数据结构的。 这个过程是在下面的方法中执行的,我们来看一下,具体的操作过程:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //创建DocumentReader来对XML格式的BeanDefinition进行解析    
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //获得容器中已经存在的Bean数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    //具体的解析过程在这个方法中执行
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

Bean定义资源的解析分为以下两个过程:

  • 通过调用xml解析器,将资源定义文件转换为Document对象,document对应并没有按照spring bean的规则进行解析。
  • 在完成通用xml解析之后,按照Spring的Bean规则对Document对象进行解析,这个过程是在documentReader中实现的。具体的操作是由DefaultBeanDefinitionDocumentReader完成的。
    处理的结果由BeanDefinitionHolder对象持有。解析过程由BeanDefinitionParserDelegate来实现。

来看下面的流程:

//根据Spring DTD 对bean定义的规则解析Bean定义Document对象
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    //获取xml描述符
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    //获得Document的根对象
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    //BeanDefinitionParserDelegate中定义了Spring Bean定义的XML文件的各种元素
    //默认BeanDefinitionParserDelegate会处理”http://www.springframework.org/schema/beans“命名空间下元素及其属性
    this.delegate = createDelegate(getReaderContext(), root, parent);
    
    if (this.delegate.isDefaultNamespace(root)) {
        //对于默认的命名空间,首先开始的是对profile属性解析
        //profile用得最多的是DataSource在不同环境下使用不同的bean
        //spring使用StringTokenizer来进行字符串的分割,但是jdk为了兼容性是推荐使用String.split()方法的:
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +"] not matching: " + getReaderContext().getResource());
                    }
                    return;
            }
        }
    }
    //接下来的解析使用了模板模式
    //进行自定义的解析,增强解析过程的可扩展性 ,空实现
    preProcessXml(root);
    //从Document的根元素开始进行Bean定义的document对象
    parseBeanDefinitions(root, this.delegate);
    //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性。空实现
    postProcessXml(root);
    this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
    delegate.initDefaults(root, parentDelegate);
    return delegate;
}

解析document文件,不同的命名的空间采用不同的方法处理

protected void parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate) {
    //Bean定义的Document对象使用了Spring默认的XML命名空间
    if (delegate.isDefaultNamespace(root)) {
        //获取Document对象的所有子节点,NodeList的含义上面进行了介绍
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);  //获取Node节点
            //判断Node是否是Element类型
            if (node instanceof Element) {
                Element ele = (Element) node;
                //判断该元素是否属于Spring定义Bean的默认命名空间
                if (delegate.isDefaultNamespace(ele)) {
                    //使用Spring的Bean规则解析元素节点
                    parseDefaultElement(ele, delegate);
                }
                else {
                    //使用用户自定义的规则进行解析
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        //没有使用spring默认的命名空间,则使用用户自定义的解析规则解析
        delegate.parseCustomElement(root);
    }
}

使用spring的Bean规则解析Document元素节点,有些元素节点是<import> <bean> 等,则分别进行解析

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //如果元素节点是<Import>导入元素,进行导入解析
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    //如果元素节点是<Alias>别名元素,进行别名解析
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    //如果是<bean>转入此流程处理
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    //如果是<beans>转入此流程处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
        doRegisterBeanDefinitions(ele);
    }
}

主要看一下对bean标签的解析过程。

protected void processBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate) {
    //BeanDefinitionHolder是对BeanDefinition的封装,delegate解析完成后使用holder封装,bdHolder 包含了id ,别名和BeanDefinition的信息
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            //向容器注册封装后的实例
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            ....
        }
        //在Beandefinition向IoC容器注册完成以后,发送消息
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

下面看一下parseBeanDefinitionElement()方法的具体实现,对于BeanDefinition的注册时存放在ConcurrentHashMap中的,beanName变为存放的健:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    //获取id的值
    String id = ele.getAttribute(ID_ATTRIBUTE);
    //获取name的值
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    //分割name属性
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
    }
    //将id赋值给beanName 
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("....");
        }
    }

    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //该方法引发对Bean元素的详细解析
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    //程序执行到此处,整个<bean>标签的解析就算结束了。一个beanDefinition就创建好了
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    //如果不存在beanName,那么根据Spring中的提供的命名规则为当前bean生成对应的beanName
                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("....");
                }
            }
            catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            //将信息封装到BeanDefinitionHolder中
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }
    return null;
}

BeanDefinition可以看成是对<bean>定义的抽象,这个数据对象中封装的数据大多都是与<bean>定义相关的,也有很多就是我们在定义Bean时看到的那些Spring标记。这个BeanDefinition数据类型是非常重要的,它封装了很多基本数据,这些都是Ioc容器需要的,上面代码最后我们返回了一个BeanDefinitionHolder实例,这个实例封装了beanDefinition,beanName, aliase三个信息,beanDefinition中也包含了beanName,aliase信息。

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));
    //这里只读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去,只是做个记录,并不涉及对象的实例化过程,对象的实例化过程实际是在依赖注入时完成的
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }

    try {
        //解析parent属性
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        //创建用于承载属性的AbstractBeanDefinition类型的GenereicBeanDefinition
        //这里生成需要的BeanDefinition对象,为Bean定义的信息做载入做准备
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        //这里对当前Bean元素进行属性解析,并设置description信息
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        //解析元数据
        parseMetaElements(ele, bd);
        //解析lookup-method属性
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        //解析replaced-method属性
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        //解析构造函数参数
        parseConstructorArgElements(ele, bd);
        //解析property子元素
        parsePropertyElements(ele, bd);
        //解析qualifier子元素
        parseQualifierElements(ele, bd);

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));
        //返回BeanDefinition对象
        return bd;
    }
    catch (ClassNotFoundException ex) {
        ...
    }
    catch (NoClassDefFoundError err) {
        ...
    }
    catch (Throwable ex) {
        ...
    }
    finally {
        this.parseState.pop();
    }
    return null;
}

从上面的代码可以看出,要解析属性首先要创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例,而代码createBeanDefinition(className,parent)的作用就是实现此功能。创建完承接的实例后,便可以进行各种属性的解析了,首先进行解析的是在<bean></bean>标签中定义的各种属性,如scope, singleton,abstract,lazy-init等,然后再解析子标签中的属性,如:lookup-method ,constructor-arg等。解析完成之后关联到实例上,之所以能进行关联,是因为xml中所有的配置都能在GenericBeanDefinition的实力类中找到对应的配置。 此时容器还没有起作用,要想起作用,需要向容器进行注册。

分析到这,已经完成了xml文件向BeanDefinition的转化,每个一个<bean>标签都会转化成一个BeanDefinition对应的实体。实体中包含了<bean>中定义的所有属性。

BeanDefinition在IOC容器中的注册

前面只是进行了BeanDefinition在IOC容器中的载入和解析过程,这些动作完成后,已经完成了定义的数据转化为BeanDefinition的过程。下面代码继续执行,看一下注册的过程,也就是processBeanDefinition函数中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry())的代码。

//registerBeanDefinition()方法的具体实现
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {

    //获取beanName
    String beanName = definitionHolder.getBeanName();
    //使用beanName作为唯一标识注册
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    //如果解析的BeanDefinition有别名,也要根据别名在注册一遍,不然根据别名找不到相应的信息
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            //beanName -> alias ,先将alias转换为beanName,在查找
            registry.registerAlias(beanName, alias);
        }
    }
}

最终承接注册任务方法是在DefaultListableBeanFactory类中定义的,为了更好的排版,我对下面的代码进行了删减,主要删除了抛出异常信息和日志信息,并不影响代码的逻辑,对于beanDefinition的注册,做了一些验证之后,直接将beanDefinition放入了Map中:

 //向IoC容器注册解析的BeanDefiniton 
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
    
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
             //注册前的最后一次校验
            //主要是对AbstractBeanDefinition属性中的methodOverrides校验
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            ....
        }
    }

    BeanDefinition oldBeanDefinition;
    //检查是否有同名的beanName存在,判断allowBeanDefinitionOveriding属性
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
                throw ...
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("....");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("....");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("...");
                }
            }
            //如果允许覆盖则执行覆盖操作
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {

            //判断是否已经有其他的Bean开始初始化
            //在容器启动的最后会预初始化所有的singleton beans
            if (hasBeanCreationStarted()) {
                //注册的过程中需要线程同步,以保证数据的一致性 
                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 {
                //正常情况下应该走此分支
                //将BeanDefinition放入Map中,此map中保存了所有的BeanDefinition
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //这个ArrayList中会按照bean配置的顺序保存每一个注册的Bean的名字
                this.beanDefinitionNames.add(beanName);
                //手动注册singleton bean 
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

依赖注入

执行完上面的操作后,IOC容器已经实现了对Bean管理定义的相关数据,但是此时IOC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况下发生:

  • 用户第一次通过getBean()方法想容器索取时,进行依赖注入
  • 当用户在Bean的定义中为<bean>配置了lazy-init属性,让容器在解析注册时进行欲初始化,触发依赖注入

AbstactBeanFactory 通过getBean()函数获取被管理的Bean,但是因为lazyinit默认为false,所以spring会进行部分实例的初始化操作,让我们回退到AbstactApplicationContext类的finishBeanFactoryInitialization(beanFactory)方法,该方法进行了所有单例类的初始化操作,初始化的动作包装在了getBean()方法中,这个方法是获取Bean的地方,也是依赖注入发生的地方,对genBean的调用会转入到doGetBean()方法来执行,来看一下该方法的定义:

//根据执行的名称获取容器管理的Bean,已经初始化就直接返回,否则就先初始化在返回
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {
    //提取定义的beanName,如果是别名,则将别名转换成规范的BeanName
    final String beanName = transformedBeanName(name);
    //定义Bean
    Object bean;

    //检查缓存中或者实例工厂中是否有对应的实例,单例模式的bean只创建一次
    Object sharedInstance = getSingleton(beanName);
    //如果实例已经创建,进入if分支 ,简单介绍一下参数args,一般情况下args为null,如果args不为null,则不是为了得到bean,而是为了创建bean
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("...");
            }
            else {
                logger.debug("...");
            }
        }
        //返回对应的实例,getObjectForBeanInstance完成的是FactoryBean的相关处理,已取得FactoryBean的生产结果,此处是FactoryBean和BeanFactory有区别。一个是创建工厂,一个是管理Bean工厂不一样。
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        //只有在单例情况下才会尝试解决循环依赖的问题,所谓循环依赖,是指:A中有B,B中有A , 形成了互相的引用
        if (isPrototypeCurrentlyInCreation(beanName)) {
            // 缓存中有指定名字的Bean但是由于循环引用创建失败了
            throw new BeanCurrentlyInCreationException(beanName);
        }
        //检查一下这个BeanDefinition在容器中是否存在
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            //如果当前容器不存在这个BeanDefinition,检查父容器中是否存在
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                //返回父容器的查询结果
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                //委派父级容器进行查找
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        //不仅仅是做类型检查, 这里要进行记录
        if (!typeCheckOnly) {
            //向容器标记指定的Bean已经被创建
            markBeanAsCreated(beanName);
        }
        try {
            //执行到这,需要创建新的Bean了。无论是单例还是原型。根据名字获取Beandefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            //先初始化所有的依赖bean
            //注意这里的依赖是指定义在depends-on中的依赖
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    //检查一下循环依赖
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(。。。);
                    }

                    //注册依赖关系
                    registerDependentBean(dep, beanName);
                    //先初始化依赖项
                    getBean(dep);
                }
            }

            //创建单例模式Bean实例
            if (mbd.isSingleton()) {
                //使用了匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            //创建bean,如果有父级继承,则合并子类和父类的定义
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //销毁单例beanName对象实例
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                //获取给定beanName的实例对象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            //创建prototype的实例
            else if (mbd.isPrototype()) {
                //原型模式每次都会创建一个新的对象
                Object prototypeInstance = null;
                try {
                    //回调beforPrototypeCreateion方法,默认的功能是注册当前创建的原型对象
                    beforePrototypeCreation(beanName);
                    //创建实例
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    //回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定bean的原型对象不在创建了
                    afterPrototypeCreation(beanName);
                }
                //获取给定的beanName实例对象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            //如果不是单例或者原型的话,则委托给响应的实现类来处理,例如request ,session , application等生命周期
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("...");
                }
                try {
                    //使用匿名内部类获取一个指定生命周期范围的实例
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        beforePrototypeCreation(beanName);
                        try {
                                return createBean(beanName, mbd, args);
                        }
                        finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    //获取给定Bean的实力对象
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(...);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    //最后检查一下类型对不对,不对的话就抛出异常,对的话就返回
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug(....);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    //将bean返回,此时的bean已经包含了依赖关系
    return (T) bean;
}

OK,上面的流程走完了,接下来该分析分支方法了, 没错,就是那个方法crateBean(),其定义如下:

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        //确保BeanDefinition中的class被加载
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        //准备方法覆写,涉及到一个概念:MethodOverrides,来自于Bean定义的<lookup-method>和<replaced-method>。感兴趣的自行研究
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            //让BeanPostProcessors 有机会返回一个代理实例而不是bean实例
            //要彻底了解清楚这个,需要看InstantiationAwwareBeanPostProcessor接口
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }
        //核心方法,创建bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

继续来看 doCreateBean()方法:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {

        //这个BeanWrapper是用来持有创建出来的Bean对象的
        BeanWrapper instanceWrapper = null;
        
        if (mbd.isSingleton()) {
            //如果是singleton,先把缓存中的同名Bean清除
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //创建Bean的地方,由crateBeanInstance完成
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //这个就是Bean里面定义的类的实例
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null):
        mbd.resolvedTargetType = beanType;

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        //解决循环依赖问题
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //负责装配属性,给属性赋值
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {

                //  处理初始化后的各种回调
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(。。。);
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(。。。);
        }

        return exposedObject;
    }

到此,doCreateBean方法便执行完了,上面的方法主要执行了三个步骤:

  • 创建Bean实例createBeanInstance方法
  • 依赖注入populateBean方法
  • 回调方法initializeBean

下面介绍与依赖注入关系特别密切的方法createBeanInstance和populateBean方法。这个方法的主要作用就是实例化我们指定的类。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        //确保已经加载了此class
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        //校验这个类的访问权限
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(....);
        }

        if (mbd.getFactoryMethodName() != null)  {
            //采用工厂方法实例化
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        //使用构造函数实例化
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                //构造函数注入
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                //无参构造函数
                return instantiateBean(beanName, mbd);
            }
        }

        //判断是否采用有参构造函数
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            //构造函数依赖注入
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        //调用无参构造函数
        return instantiateBean(beanName, mbd);
    }

在创建实例时,重要的是下面代码:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

继续跟进一下:

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides.
        if (bd.getMethodOverrides().isEmpty()) {
            Constructor<?> constructorToUse;
            synchronized (bd.constructorArgumentLock) {
                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    final Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }
                    try {
                        if (System.getSecurityManager() != null) {
                            constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                                @Override
                                public Constructor<?> run() throws Exception {
                                    return clazz.getDeclaredConstructor((Class[]) null);
                                }
                            });
                        }
                        else {
                            constructorToUse =  clazz.getDeclaredConstructor((Class[]) null);
                        }
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            // Must generate CGLIB subclass.
            return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }

判断一下是否存在方法覆写,如果不存在就使用java反射的方式创建实例,否则使用CGLIB来创建实例。

在这简单说一下,spring创建Bean的两种方式,一种是通过BeanUtis(JVM的反射功能,必须要基于接口才能实现),另一种就是CGLIB来生成。具体的不做深入分析,会放入AOP中来说明。到这实例的创建就完成了, 下面说一下属性的注入.

bean 属性注入,上面的代码已经完成了Bean对象的实例化,实例化对象已经生成,怎样把这些Bean对象的依赖关系处理好,依赖关系已经保存在了BeanDefinition中,看下面的方法:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
   //获取property的值。来自于BeanDefinition中。
   PropertyValues pvs = mbd.getPropertyValues();
   //判断实例是否为空
   if (bw == null) {
      //实例为空,属性不为空,抛出异常
      if (!pvs.isEmpty()) {
         throw new BeanCreationException(。。。);
      }
      else {
         return;
      }
   }
 
   // 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
   // InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改,
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }
 
   if (!continueWithPropertyPopulation) {
      return;
   }
    //开始进行依赖注入过程,先处理autowire的注入
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
 
      // 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
 
      // 通过类型装配。复杂一些
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
 
      pvs = newPvs;
   }
 
   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
 
   if (hasInstAwareBpps || needsDepCheck) {
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               // 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
               // 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的,不过本文不会展开说了,感兴趣的读者请自行研究
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   // 设置 bean 实例的属性值
   applyPropertyValues(beanName, mbd, bw, pvs);
}

initializeBean
属性注入完成后,这一步其实就是处理各种回调了。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
      // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
      invokeAwareMethods(beanName, bean);
   }
 
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessBeforeInitialization 回调
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      // 处理 bean 中定义的 init-method,
      // 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
 
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessAfterInitialization 回调
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

终于简单的分析完了,太不容易了。 spring的分支是在是太多了。很多地方都没有进行深究。以后有机会再慢慢看吧。

参考:
spring技术内幕
spring 源码分析
https://zhuanlan.zhihu.com/p/29344811
http://www.importnew.com/27469.html

Spring
Web note ad 1