Spring IOC 实现原理

作者: 起个名忒难 | 来源:发表于2018-05-17 23:08 被阅读1150次

    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 IOC 实现原理

      本文链接:https://www.haomeiwen.com/subject/gxbjlftx.html