《Spring技术内幕》---------IoC容器的实现 - Go语言中文社区

《Spring技术内幕》---------IoC容器的实现


1.Spring的整体架构

Spring IoC:包含了最基本的IoC容器的BeanFactory的接口与实现。BeanFactory系列容器只实现了最基本的IoC容器的功能;ApplicationContext应用上下文,作为容器的高级形态存在,增加了许多面向框架的特性,包括国际化和应用支持。

Spring Aop:集成AspectJ作为AOP的一个特定实现,同时还在JVM动态代理和CGLIB的基础上,实现了AOP框架;声明式事务,日志处理,权限判断。

Spring MVC:以DispatcherServlet为核心,实现了MVC模式,包括怎样与Web容器集成,Web请求的拦截、转发、处理和ModelAndView数据的返回。

Spring JDBC/ORM:对JDBC进行封装,使得通过JDBC完成的对数据库的操作更加方便,还提供了JdbcTemplate作为模板类,封装了基本数据库的操作方法。还提供了许多ORM工具的封装,例如HibernateTemplate等。

Spring事务处理:通过Spring AOP实现自身功能增强的典型模块。

Spring 远端调用:通过Spring的封装从Spring应用到Spring应用之间的端到端的调用。在这个过程中,通过Spring的封装,为应用屏蔽了各种通信和调用的细节,从而可以使用不同的远端调用来实现,HTTP调用器已经传统的RMI调用。

Spring 应用:通过这个模块使得Spring应用能够简洁的容纳第三方的技术实现,丰富了Spring的应用功能。

2.Spring IoC容器的概述

控制反转,控制权的反转,控制权从具体业务对象手中转到IoC容器中;如果相关对象的引用或依赖关系的管理由具体对象来完成,会导致代码的高度耦合。对象的依赖关系往往体现在对数据和方法的依赖上,这些依赖关系可以通过把对象的依赖注入交给框架或者IoC容器来完成,这种控制权的转移能够降低耦合提高可测试性。

控制反转的实现有很多种方式,可以在对象初始化时,就进行数据注入,也可以通过对象引用注入到数据域中实现。对象之间的相互依赖关系由IoC容器进行管理,并由IoC容器完成对象的注入。

2.1IoC容器的设计

①BeanFactory-HierachicalBeanFactory-ConfigurableBeanFactory,HierachicalBeanFactory继承了BeanFactory,增加了getParentBeanFactory的接口功能,ConfigurableBeanFactory接口,主要定义了一些对BeanFactory的配置功能。

②BeanFactory-ListableBeanFactory-ApplicationContext-ConfigurableApplicationContext,ListableBeanFactory细化了好多BeanFactory的接口功能,如定义了getBeanDefinitionNames接口方法,ApplicationContext通过集成MessageSource、ResourceLoader、ApplicationEventPublisher接口,添加了许多对高级容器的特性支持。

BeanFactory与FactoryBean,BeanFactory是IoC容器或者对象工厂,所有的Bean都是由BeanFactory进行管理的。FactoryBean是一个能够产生对象的工厂Bean,使用&可以得到FactoryBean本身,不会得到FactoryBean产生的对象

 

2.1.1BeanFactory的应用场景

BeanFactory的getBean方法,可以取得IoC容器中管理的Bean,通过指定名字来索引,还可以带Bean的类型,或者prototype类型的参数。

2.1.2 BeanFactory容器的设计原理

以XmlBeanFactory为例,简单说明IoC容器的设计原理

只提供最基本的IoC容器的功能。XmlBeanFactory继承了DefaultListableBeanFactory这个类,DefaultListableBeanFactory是经常需要用到的一个IoC的实现,ApplicationContext就会使用到该类,它包含了基本IoC容器所具有的重要功能。XmlBeanFactory在DefaultListableBeanFactory的基础上增加了可以读取xml文件定义的BeanDefinition的功能。实现过程如下

XmlBeanFactory中初始化了一个XmlBeanDefinitionReader对象,该对象那个可以处理xml方式定义的BeanDefinition。构造XmlBeanFactory的时候,需要指定BeanDefinition的信息来源(某个xml文件),而这个信息来源需要封装成Resource类(用来封装IO的类),例如ClassPathResource res = new ClassPathResource(“beans.xml”);将resource作为构造参数传入到XmlBeanFactory的构造器中,调用loadBeanDefinition方法,从Resource中载入BeanDefinition。

理解编程方式使用IoC容器

①创建IoC配置文件的抽象资源Resource,包含了BeanDefinition的定义

②创建一个BeanFactory,这里使用DefaultListableBeanFactory

③创建一个载入BeanFactory的读取器,使用XmlBeanDefinitionReader来载入xml文件形式的BeanDefinition。

④调用loadBeanDefinition,完成载入信息操作,载入和注册bean后,就可以使用IoC容器了。

2.1.3ApplicationContext的应用场景

ApplicationContext是一个高级形态意义的IoC容器,提供了一些附加功能

①继承了MessageSource接口,支持国际化实现

②继承了ResourceLoader接口,可以从不同地方得到Bean定义资源

③继承了ApplicationEventPublisher接口,引入了事件机制,与Bean生命周期结合为Bean的管理提供便利。

2.1.4 ApplicationContext容器的设计原理

以FileSystemXmlApplicationContext的实现为例

ApplicationContext主要功能已经在AbstractXmlApplicationContext中实现了,FileSystemXmlApplicationContext只需要实现与其自身设计相关的功能即可

①如果直接使用FileSystemXmlApplicationContext,对于实例化ApplicationContext的支持,同时启动IoC容器的refresh过程

②怎样从文件系统中加载xml的bean定义资源

从xml中得到BeanDefinition的抽象资源,然后返回Resource

2.2 IoC容器的初始化过程

IoC的初始化过程是由refresh来启动,这个方法标志着IoC容器的正式启动。启动过程包括BeanDefinition的Resource定位、BeanDefinition的载入和BeanDefinition的注册。

Spring把三个过程分开,并使用不同模块来完成,通过这样的设计方式,可以让用户更加灵活地对这三个过程进行裁剪和扩展。

①Resource定位,由ResourceLoader通过统一的Resource接口来完成,可以使用上述getResourceByPath完成,也可以使用ClassPathResource来完成。

②BeanDefinition载入,用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器的内部数据结构就是BeanDefinition。

③注册BeanDefinition,调用BeanDefinitionRegistry接口实现。IoC容器内部将BeanDefinition注入到一个HashMap中去,通过HashMap持有这些BeanDefinition

注意:一般来说初始化和依赖注入是两个分开的过程,依赖注入是在第一次调用getBean时进行的,即默认的lazyinit属性是true,有个例外,对bean设置了lazyinit属性为false,并且是singleton之后,那么这个Bean的依赖注入就会在容器初始化时就预先完成了。如果是prototype类型,那么即使lazyinit是false,那么也不会在初始化就进行依赖注入,详情见DefaultListableBeanFactory中的preInstantiateSingletons()方法

2.2.1 Resource定位

以FileSystemXmlApplicationContext为例,通过继承AbstractApplicationContext具备了ResourceLoader从Resource中读入BeanDefinition的能力;

getResourceBypath方法用于BeanDefinition的定位,构造器中的refresh方法用于实现BeanDefinition的载入过程。FileSystemXmlApplicationContext的refresh方法调用AbstractRefreshableApplicationContext的refreshBeanFactory方法。refreshBeanFactory通过createBeanFactory构建了一个IoC容器供ApplicationContext使用,就是defaultlistableBeanfactory,然后调用loadBeanDefinitions来载入BeanDefinition,方法参数就是defaultlistableBeanfactory;该过程实际上调用的是AbstractApplicationContext里面的loadBeanDefinitions,然后初始化了XmlBeanDefinitionReader,调用loadBeanDefinitions(XmlBeanDefinitionReader reader)方法,里面有获取getConfigLocations,之后就会在AbstractBeanDefinitionReader里面的loadBeanDefinitions(String location, Set<Resource> actualResources)方法getResourceLoader,此时get到的ResourceLoader就是FileSystemXmlApplicationContext,然后就会调用ResourceLoader的getResource方法,由于FileSystemXmlApplicationContext继承了DefaultResourceLoader,所以调用其中的getResource方法;如下。

由于FileSystemXMLApplicationContext设定了configLocation,所以用的是reader.loadBeanDefinitions(configLocations);这个方法,此方法在getResource得到Resource之后就会进行BeanDefinition的载入

由于AbstractBeanDefinitionReader没有实现loadBeanDefinitions(resource);因此调用xmlBeanDefinitionReader类中的loadBeanDefinitions(resource);进行载入;

2.2.2 BeanDefinition的载入和解析

Refresh方法的实现,是在AbstractApplicationContext中,代码如下,BeanFactory的更新,此方法在AbstractRefreshableApplicationContext类的refreshBeanFactory方法

如果有旧的beanFactory,就销毁和关闭并且创建新的BeanFactory;MessageSource和PostProcessor的注册等。

真正BeanDefinition的载入过程在refreshBeanFactory方法中

loadBeanDefinitions是一个抽象方法,在AbstractXmlApplicationContext中实现,在该方法中,初始化了XmlBeanDefinitionReader,然后把这个读取器在IoC容器中设置好,在loadBeanDefinitions(beanDefinitionReader);调用reader.loadBeanDefinitions(configLocations)完成BeanDefinition的载入

然后就是loadBeanDefinitions调用,首先得到Resource定位,具体由子类进行,此时由于FileSystemXmlApplicationContext不是ClassPathXmlApplicationContext,所以configResources返回null,进行getConfigLocation载入。

reader.loadBeanDefinitions(configLocations)在AbstractBeanDefinitionReader中,然后进行资源的定位以及载入;

上面已经分析过,得到resource之后,进行真正的载入过程,此时的loadBeanDefinitions(resource)在XmlBeanDefinitionReader中,

得到输入流之后,就可以采用doLoadBeanDefinitions方法进行xml文件解析

获取Document对象,采用SAX解析xml;Spring的BeanDefinition是怎么样按照Spring的Bean语义要求进行解析并转化为内部数据结构的,这个过程由registerBeanDefinitions完成;

parseBeanDefinition到下面的方法

创建一个BeanDefinitionDocumentReader,默认是DefaultBeanDefinitionDocumentReader,使用BeanDefinitionParserDelegate进行解析Document对象,解析后的结果

放在BeanDefinition中,并将beanName,aliase作为参数保存到BeanDefinitionHolder中。

一层一层调用解析,这样xml中定义的BeanDefinition就被载入到IoC容器中了,并在容器中建立了数据的映射。这个时候容器还没有完全起作用,要完全发挥容器作用,还需要进行注册

2.2.3 BeanDefinition在IoC中的注册

载入和解析过程,已经将用户定义的BeanDefinition信息在IoC容器中建立起了自己的数据结构,但是还需要进行注册才能使用。在DefaultListableBeanFactory中,通过一个ConcurrentHashMap来持有载入的BeanDefinition

在xmlBeanDefinitionReader传入的DefaultListableBeanFactory,就是设定AbstractBeanDefinitionReader中的registry为DefaultListableBeanFactory。因此在DefaultBeanDefinitionDocumentReader的processBeanDefinition方法中BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());就是用来注册BeanDefinition;

调用的是DefaultListableBeanFactory的registerBeanDefinition(String, BeanDefinition)方法

 

注册之后,BeanDefinition就可以被使用了。

2.3 依赖注入

依赖注入过程是用户第一次调用getBean时触发的,例外就是lazy-init属性的预实例化,后面会讲。GetBean调用完之后会触发doGetBean;就是用于依赖注入;getBean-dogetBean-createbean;

AbstractBeanFactory中的dogetBean方法会调用AbstractAutowireCapableBeanFactory的CreateBean方法;该方法生成了需要的bean,还对bean初始化进行了处理,定义后置处理器,定义init-method属性等;createBean中调用了doCreateBean方法

该方法中主要就是createBeanInstance和populateBean方法,createBeanInstance生成了Bean所包含的java对象,这个对象的生成有很多种不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成。

使用不同的方式进行bean的实例化

使用cglib进行bean实例化,cglib是一个常用的字节码生成器的类库,提供了生成和转换字节码的功能。Cglib如何生成bean对象需要看simpleInstantiationStrategy。提供了两种实例化对象的方法,一种是BeanUtils,使用JVM的反射功能,一种使用cglib生成

实例化对象后,需要为依赖关系进行处理,即使用populateBean方法,在AbstractAutowireCapableBeanFactory中;

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {

获取BeanDefinitionproperty属性值

       PropertyValues pvs = mbd.getPropertyValues();

 

       if (bw == null) {

           if (!pvs.isEmpty()) {

              throw new BeanCreationException(

                     mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");

           }

           else {

              // Skip property population phase for null instance.

              return;

           }

       }

       boolean continueWithPropertyPopulation = true;

开始依赖注入过程,先处理autowired的注入

       if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||

              mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {

           MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

 

           autowired注入的处理,可以根据名字或者类型来完成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;

                     pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

                     if (pvs == null) {

                         return;

                     }

                  }

              }

           }

           if (needsDepCheck) {

              checkDependencies(beanName, mbd, filteredPds, pvs);

           }

       }

         然后对属性进行注入

       applyPropertyValues(beanName, mbd, bw, pvs);

    }

 

通过applyPropertyvalues了解具体的对属性行进行解析然后注入的过程

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {

       if (pvs == null || pvs.isEmpty()) {

           return;

       }

 

       MutablePropertyValues mpvs = null;

       List<PropertyValue> original;

 

       if (System.getSecurityManager() != null) {

           if (bw instanceof BeanWrapperImpl) {

              ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());

           }

       }

 

       if (pvs instanceof MutablePropertyValues) {

           mpvs = (MutablePropertyValues) pvs;

           if (mpvs.isConverted()) {

              // Shortcut: use the pre-converted values as-is.

              try {

                  bw.setPropertyValues(mpvs);

                  return;

              }

              catch (BeansException ex) {

                  throw new BeanCreationException(

                         mbd.getResourceDescription(), beanName, "Error setting property values", ex);

              }

           }

           original = mpvs.getPropertyValueList();

       }

       else {

           original = Arrays.asList(pvs.getPropertyValues());

       }

 

       TypeConverter converter = getCustomTypeConverter();

       if (converter == null) {

           converter = bw;

       }

       

        这个BeanDefinitionValueResolverBeanDefinition的解析是在这个valueResolver中完成的

       BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

为解析之后的属性值创建一个副本,副本数据将会被注入到bean

       // Create a deep copy, resolving any references for values.

       List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());

       boolean resolveNecessary = false;

       for (PropertyValue pv : original) {

           if (pv.isConverted()) {

              deepCopy.add(pv);

           }

           else {

              String propertyName = pv.getName();

              Object originalValue = pv.getValue();

根据需要解析的内容,originalValuepropertyName判断是reference还是list还是其他集合

              Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

              Object convertedValue = resolvedValue;

              boolean convertible = bw.isWritableProperty(propertyName) &&

                      !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);

              if (convertible) {

                  convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);

              }

              // Possibly store converted value in merged bean definition,

              // in order to avoid re-conversion for every created bean instance.

              if (resolvedValue == originalValue) {

                  if (convertible) {

                     pv.setConvertedValue(convertedValue);

                  }

                  deepCopy.add(pv);

              }

              else if (convertible && originalValue instanceof TypedStringValue &&

                     !((TypedStringValue) originalValue).isDynamic() &&

                     !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {

                  pv.setConvertedValue(convertedValue);

                  deepCopy.add(pv);

              }

              else {

                  resolveNecessary = true;

                  deepCopy.add(new PropertyValue(pv, convertedValue));

              }

           }

       }

       if (mpvs != null && !resolveNecessary) {

           mpvs.setConverted();

       }

这里是依赖注入发生的地方,会在beanWrapperImpl中完成

       // Set our (possibly massaged) deep copy.

       try {

           bw.setPropertyValues(new MutablePropertyValues(deepCopy));

       }

       catch (BeansException ex) {

           throw new BeanCreationException(

                  mbd.getResourceDescription(), beanName, "Error setting property values", ex);

       }

    }

 

 

大致过程:第一个调用getBean的时候,getBean会调用AbstractBeanFactory的createBean方法;createBean方法会调用doCreateBean方法得到一个Bean的引用;doCreateBean方法中定义了一个BeanWrapper用来持有创建出来bean对象,主要有两个过程,一是实例化bean,二是设置bean的依赖关系;createInstance方法中有两种方法对bean进行实例化,通过BeanUtils,使用jvm反射,一种是使用cglib生成;实例化对象之后,就需要设置bean的依赖关系;populateBean方法中先取得载入解析过程的property的值;先处理autowire的注入,根据bean的名字,类型等;然后处理property的注入;调用applyPropertyValues方法;方法中定义了一个BeanDefinitionValueResolver,设定一个需要注入的属性值的副本deepcopy,遍历属性值,使用解析器BeanDefinitionValueResolver进行属性值的解析;然后添加到deepcopy中。

上述的过程是为解析准备条件,真正把bean对象设置到另外一个依赖bean是在bw.setPropertyValues(new MutablePropertyValues(deepCopy));具体是在子类中实现了注入过程;通过几个地方的递归将,集合map,list和非集合的属性值注入到bean中,然后返回到BeanWapper,最终得到注入完成的Bean的实例。

2.4 容器其他相关特性的设计与实现

2.4.1 ApplicationContext和Bean的初始化及销毁

在容器要关闭的时候,也需要完成一系列的工作,这些工作在doClose方法中完成。在这个方法中,先发出容器关闭信号,然后将Bean逐个关闭,最后关闭容器自身。

容器的实现是通过IoC管理Bean的生命周期实现的。

 

Bean的生命周期:

①bean的初始化和实例化

②设置bean的属性,依赖注入

③应用可以通过IoC容器使用bean

④当容器关闭时,调用bean的销毁方法

Bean的初始化方法调用在initializeBean中实现:该方法在AbstractAutowireCapableBeanFactory类中

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {

       if (System.getSecurityManager() != null) {

           AccessController.doPrivileged(new PrivilegedAction<Object>() {

              @Override

              public 版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/huangwei18351/article/details/82953688
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

  • 发表于 2020-02-25 00:37:50
  • 阅读 ( 955 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢