Spring的IOC容器源码学习----Bean的定位,载入,解析,注册,注入

目录

BeanFactory

ApplicationContext

1.IOC初始化过程

1.1 BeanDefinition的Resource的定位

1.2 BeanDefinition的载入和解析

1.3 BeanDefinition在IOC容器中的注册

1.4 IOC容器的依赖注入


IOC容器系列包含BeanFactory和ApplicationContext,这两个接口就是IOC的具体表现形式。

他们的接口关系设计图如下所示:

主要接口设计主线:

  •    1.BeanFactory -> HierarchicalBeanFactory->ConfigurableBeanFacotry
  •    2.BeanFactory -> ListableBeanFactory -> ApplicationContext -> WebApplicationContext/ConfigurableApplicationContext

我们常用的应用上下文就是WebApplicationContext/ConfigurableApplicationContext的实现。

BeanFactory

DefaultListableBeanFactory这个基本IOC容器的实现就是实现了ConfigurableBeanFactory,而其他的都是在这个类上做扩展。

一般在使用IOC容器的时候,需要如下几个步骤:

      1.创建IOC配置的抽象资源,这个抽象资源包含了BeanDefinition的定义信息

     2.创建一个BeanFactory,比如DefaultListableBeanFactory

     3.创建一个载入BeanDefinition的读取器,例如XmlBeanDefinitionReader来载入xml文件形式的BeanDefinition,通过一个回调配置给BeanFactory

    4.从定义好的资源位置读入配置信息,具体的解析过程就交给XMLBeanDefinitionReader来完成,完整的在和注册Bean定义之后,需要的Ioc容器就建立好了,这时候就可以使用Ioc容器了

      比如我们之前用的XmlBeanFactory,现在已经废弃使用了。

        ClassPathResource classPathResource = new ClassPathResource("beans.xml");
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.loadBeanDefinitions(classPathResource);

ApplicationContext

相比使用BeanFactory,大家更偏向使用功能更加强大的ApplicationContext,他在BeanFactory的基础上添加了很多BeanFactory不具备的功能,

   1)支持不同的消息源。ApplicationContext扩展了MessageSource接口,这是信息源的扩展能工可以支持和国际化的实现,为开发多语言版本的应用提供了服务

  2) 访问资源,我们对于ResourceReader和Resource的支持,可以从多个角度获取资源。

  3) 支持应用实践。继承了接口ApplicationEventPubliser,从而在上下中引入了时间机制,这些事件和Bean的生命周期的结合为Bean的管理提供了遍历

 4)在ApplicationContext中提供了附加服务,是的ApplicationContext更像面向框架的使用风格。建议开发中使用ApplicationContext作为Ioc容器的基本形式。

例如:ClassPathXmlApplicationContext和FileSystemXmlApplicationContext都是抽象类AbstractXmlApplicationContext的实现,都是从xml配置文件中获取资源配置bean,前者是从类路径获取配置文件,后者是通过文件系统载入。

这两个类都是都是根据不同的形式读取resource,都是重写了抽象父类的getConfigResources模板方法。如下:

   // FileSystemXmlApplicationContext这个类中的,其他也都是构造方法,都是不同的入参调用下面这个方法 ,Class
   public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();     //这是启动整个IOC 的核心方法
        }

    }

    //这个是读取资源,封装为fileSystem资源,这里重写了父类的模板方法
    protected Resource getResourceByPath(String path) {   
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }

        return new FileSystemResource(path);  
    }

1.IOC初始化过程

      IOC容器的初始化都是如上面的refresh()来启动的,这个方法标志着IOC容器的正式启动,这个启动包含了BeanDefinitionResource的定位,载入和注册三个基本过程。这里把这几个过程分开做模块就是做到解耦,降低组件的耦合性。

  • 1)Resource定位过程,这个指的就是BeanDefinition(bean在IOC中的抽象存储)资源的定位,它由ResourceLoader通过统一的Resource接口来完成。
  • 2) BeanDefinition的载入,就是把用户定义好的Bean表示为IOC容器内部的数据结构,而这个容器的内部结构就是BeanDefinition。简单说BeanDefinition就是POJO对象在IOC容器中的抽象,通过这个BeanDefinition定义的数据结构,是Ioc容器能够方便对POJO对象进行管理。
  • 3) 向IOC容器中注册这些BeanDefinition的过程,这个过程就是通过BeanDefinitionRegistry接口来完成的。这个注册过程把载入过程解析得到的BeanDefinition向IOC容器进行注册。内部就是将BeanDefinition注入到一个HashMap中去,IOC容器就是通过这个HashMap来持有这些BeanDefinition数据的。

     注意点:IOC容器的初始化不包含Bean的依赖注入。Bean定义的载入和依赖注入是分开的两个过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。不过我们可以通过设置lazyinit属性,让容器在初始化的时候就让这个Bean做到依赖注入,而不用等到第一次getBean的时候调用

1.1 BeanDefinition的Resource的定位

        Resource接口的实现类图如下:      

例如:

ClassPathResource res = new ClassPathResource("bean.xml"); 

//表示从当前类路径去找寻以文件形式存在的BeanDefinition。

    但是获取到的Resource并不能直接被BeanFactory使用,这里需要使用BeanDefinitionReader对于这些信息进行处理,而例如BeanFactory的一种重要实现-DefaultListableBeanFactory只是一个纯粹的Ioc容器,需要为他配置特定的读取器才能完成想用的读取功能,而ApplicationContext就提供了许多不同的Resource的读取器来完成读取。

下面来研究FileSystemXmlApplicationContext

1)结构图

通过前面的ConfigurableApplicationContext就继承了所有ApplicationContext的所有特性,包含ResourceLoader读入和Resource定义BeanDefinition的能力。

2)这个类源码

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
    public FileSystemXmlApplicationContext() {
    }

    public FileSystemXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }
    //支持多个配置文件
    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, (ApplicationContext)null);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, (ApplicationContext)null);
    }
    //自己双亲IOC容器
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();   //调用refresh函数载入BeanDefinition。
        }

    }

    //这个方法是在BeanDefinitionReader的loadBeanDefinition方法中被调用的,loadBeanDefinition这个方法采用的模板方法,由各个子类来完成的
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }

        return new FileSystemResource(path);
    }
}

3)重点方法refresh方法分析的调用情况

          FileSystemXmlApplicationContext中的构造方法调用了的refresh方法调用了最后调用父类的父类的方法refreshBeanFactory,如下面的时序图。     

 

refreshBeanFactory方法源码如下:

 protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            //这里通过新建IOC容器。
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            //这里是模板方法在AbstractBeanDefinitionReader中可以看到具体实现.这里载入BeanDefinition
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

4)FileSystemXmlApplicationContext中的方法 getResourceByPath方法的调用关系图,上面的refresh方法会调用到FileSystemXmlApplicationContext自身的的这个方法:

1.2 BeanDefinition的载入和解析

      在完成对BeanDefinition的Resource定位之后就需要了解BeanDefinition的载入过程,这个过程相当于把定义的BeanDefinition在IOC容器中转化成一个Spring内部表示的数据结果的过程。

   1)在AbstractApplicationContext中被子类调用的refresh的方法源码:

 public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            //启动子类中的refreshBeanFacotry,包含创建IOC容器
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {            
                this.postProcessBeanFactory(beanFactory);//设置BeanFactory后置处理器
                this.invokeBeanFactoryPostProcessors(beanFactory); //调用BeanFactory的后置处理器,这些后置处理器是在bean定义中想容器注册的
                this.registerBeanPostProcessors(beanFactory);//注册bean的后置处理器,在Bean创建过程中调用
                this.initMessageSource(); //初始化上下文中的消息源
                this.initApplicationEventMulticaster();//初始化上下文中的事件机制
                this.onRefresh();//这个没有被实现
                this.registerListeners();//检查监听器并将这些bean注册
                this.finishBeanFactoryInitialization(beanFactory);//实例化所有的non-lazy-init的bean
                this.finishRefresh(); //发布容器事件,结束refresh过程
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches(); //
            }

        }
    }

2)BeanDefinition解析的时序图       

可以看到在AbstractXmlApplicationContext中的方法,可以采用XmlBeanDefinitionReader来载入BeanDefinition

  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

这里的loadBeanDefinitions方法最终是由XmlBeanDefinitionReader实现。最终处理后的结果由BeanDefinitionHolder来持有结果,除了BeanDefinition外,还包含bean的名字,别名集合,这个BeanDefinitionHolder的生成是通过对Document文档书的内容进行解析来完成的,可以知道这个解析过程是由BeanDefinitionParseDelegate来实现的,具体在processBeanDefinition中实现。

BeanDefinitionParseDelegate包含对Array,List,Set,Map,Prop等各种元素的解析,并生成相应的数据对象。我们可以以AbstractBeanDefintion为入口,让IOC容器执行索引,查询和操作。

1.3 BeanDefinition在IOC容器中的注册

        我们对BeanDefinition进行载入和解析后,需要把它向IOC容器中注册,在DefaultLIstableBeanFactory中有一个map用来存储这个的

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);

1)我们可以看到注册的调用过程如下:

 2)registerBeanDefinition的方法调用链如下所示:

由于DefaultListableBeanFactory实现了BeanDefinition接口,只需要把这个BeanDefinition设置到hashMap中即可。完成了BeanDefinition的注册,那么就完成了IOC容器的初始化偶成,此时在使用IOC容器的DefaultListableBeanFactory中已经建立的整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了。他们都是在beanDefinitionMap里被检索和使用。键名是beanName;

1.4 IOC容器的依赖注入

          依赖注入都是在用户第一次向容器获取Bean的时候触发,但是我们也可以通过控制lazyinit属性对其预实例化。当我们获取Bean的时候是通过BeanFactory中的方法getBean方法获取。其中DefaultListableBeanFactory中的getBean方法都是调用基类中的AbstractBeanFactory中的getBean方法。

1)具体源码:      

   //这里是对BeanFactory接口的实现,比如getBean方法,而这个方法实际上又是调用的doGetBean来实现的
   public AbstractBeanFactory(BeanFactory parentBeanFactory) {
        this.parentBeanFactory = parentBeanFactory;
    }

    public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }

    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return this.doGetBean(name, requiredType, (Object[])null, false);
    }

    public Object getBean(String name, Object... args) throws BeansException {
        return this.doGetBean(name, (Class)null, args, false);
    }

    public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
        return this.doGetBean(name, requiredType, args, false);
    }
    //这里是实际取得Bean的地方,也是触发依赖注入发生的地方
    protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
        final String beanName = this.transformedBeanName(name);
        //先从缓存中获取单例的bean
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        if (sharedInstance != null && args == null) {
            if (this.logger.isDebugEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            //这里的完成的是FactoryBean的相关处理,以取得FactoryBean的生产结果
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
            if (this.isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            //利用双亲BeanFactory获取
            BeanFactory parentBeanFactory = this.getParentBeanFactory();
            if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                String nameToLookup = this.originalBeanName(name);
                if (args != null) {
                    return parentBeanFactory.getBean(nameToLookup, args);
                }

                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }

            if (!typeCheckOnly) {
                this.markBeanAsCreated(beanName);
            }

            try {
                //通过Bean的名字获取BeanDefinition
                final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                this.checkMergedBeanDefinition(mbd, beanName, args);
                //获取当前Bean的依赖项,这里触发递归调用,直到没有依赖为止
                String[] dependsOn = mbd.getDependsOn();
                String[] var11;
                if (dependsOn != null) {
                    var11 = dependsOn;
                    int var12 = dependsOn.length;

                    for(int var13 = 0; var13 < var12; ++var13) {
                        String dep = var11[var13];
                        if (this.isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }

                        this.registerDependentBean(dep, beanName);
                        this.getBean(dep);
                    }
                }
                //判断是单例的情况下,使用createBean方法创建bean
                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
                        public Object getObject() throws BeansException {
                            try {
                                return AbstractBeanFactory.this.createBean(beanName, mbd, args);
                            } catch (BeansException var2) {
                                AbstractBeanFactory.this.destroySingleton(beanName);
                                throw var2;
                            }
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) {  //这里创建prototype的bean
                    var11 = null;

                    Object prototypeInstance;
                    try {
                        this.beforePrototypeCreation(beanName);
                        prototypeInstance = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }

                    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    String scopeName = mbd.getScope();
                    Scope scope = (Scope)this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }

                    try {
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            public Object getObject() throws BeansException {
                                AbstractBeanFactory.this.beforePrototypeCreation(beanName);

                                Object var1;
                                try {
                                    var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
                                } finally {
                                    AbstractBeanFactory.this.afterPrototypeCreation(beanName);
                                }

                                return var1;
                            }
                        });
                        bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } catch (IllegalStateException var21) {
                        throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var21);
                    }
                }
            } catch (BeansException var23) {
                this.cleanupAfterBeanCreationFailure(beanName);
                throw var23;
            }
        }
        //最后对bean的类型检查,通过后就返回bean,这个bean包含依赖关系的bean
        if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
            try {
                return this.getTypeConverter().convertIfNecessary(bean, requiredType);
            } catch (TypeMismatchException var22) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
                }

                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        } else {
            return bean;
        }
    }

2)getBean方法调用的时序图

重要方法是createBeanInstance和populateBean方法,这个生成bean的方式很多,可以通过工厂方式,也可以autowire,CCLIB实例化等。SimpleInstantiationStrategy类是用来生成bean对象的默认实现类,提供两种实例化java对象的方法,一种是通过BeanUtil(JVM反射技术),另外一个种就是CGLIB技术。后面通过BeanDefinitionResolver对BeanDefinition进行解析,然后注入到property中。

这里也基本都是摘录《Spring技术内幕》里面的内容。描述了一个大概的IOC内容,如有错误,欢迎指正。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值