zoukankan      html  css  js  c++  java
  • Spring-beans架构设计原理

    原文链接

    IOC

    IOC,大名鼎鼎,如雷贯耳。官方给的定义是依赖注入(Dependency Injection)或者控制反转(Inversion of Control),都相当术语化,不太容易懂。

    想象下日常中的生产过程,在生产之前是客户下单,单子上会详细注明需要的产品,包括产品的各方面规格属性,然后工厂据此生产。

    IOC就是一个类似的过程,我们声明需要什么,工厂据此给我们生产出来。在这个过程中我们只是给出了需求清单,而不用再去辛苦new,以及不停设置各种属性。

    Spring ioc

    Spring-beans是ioc最著名的实现,而且没有之一,在业界几乎也就是ioc的代名词。Beans是整个spring的基石组件,可以说所有的spring组件都是基于它。

    spring-beans整体架构

    Spring-beans提供的优秀的可扩展能力使spring几乎能包容一切,用户只需遵循spring beans的相关规范--spring.schema定义配置文档的文法规范,spring.handler定义客户化配置的解析工具--就可以将bean接入到spring容器里。Bean接入后还可以通过实现BeanPostProcessor或者init-method对bean做后处理甚至替换bean。

    Spring-beans的优秀设计使spring越来越像是一个生态圈,基于beans,aop、context、mvc、annotation等强大的组件都被接入进来,除此还有一些优秀的第三方组件,例如dubbo等。
    spring生态圈
    以aop为例,先在parse阶段对aop的配置生成Advised bean(Advisor),然后在所有bean的后处理阶段get Advised bean,并通过filter判断是否适应于当前bean,适用则会对bean织入advice。后面如果有时间会专门做篇aop,这里不再继续深入。

    Dubbo和aop略有区别,dubbo的扩展选择了init method中的afterPropertiesSet,所有严格意义上dubbo是无法去spring的,虽然dubbo声明是可以,但其实只能不适用spring功能,而不能去spring jar,dubbo bean在init阶段生成ref,其实也是个代理--封装了远程访问的细节。

    Bean定义

    Spring-beans的核心实体是BeanDefinition和BeanFactory。前者映射我们的定义,后者则是依据定义生产bean的工厂。
    beans概念模型
    上图是spring beans的静态结构图,更多是偏重于bean解析,因为1. 理解了bean解析也就理解了一半spring扩展能力;2.BeanFactory的复杂不在于类之间的组织结构,而在于复杂的调用链路,也就没必要是静态结构方面做过多说明。需要说明的是,这只是概念模型,并不完全映射到类,因为spring的抽象层次太高,一个概念实体功能往往由多个类协同完成,画起来比较费劲,就类似BeanFactory,光搞清楚各个BeanFactory之间的关系就理得头痛,所以都尽可能从概念层面说明。

    重要实体说明

    • DefaultListableBeanFactory是BeanDefintionRegistry的默认实现,它是个适配器,用于适配BeanFactory和BeanDefintionRegistry,工厂和定义通过它统一。它由ApplicationContext初始化,并被作为BeanDefinitionReader的registry。Reader对配置文档加载解析,生成definition并注册到registry--其实就是DefaultListableBeanFactory,这样工厂就拥有了类定义,bean初始化时也可以通过内部方法轻松获取到定义。
    • NamespaceHandlerResolver用于获取配置解析实体--NamespaceHandler。它和registry均内聚在上下文实体--ReaderContext中,parser内聚上下文从而可以间接访问handler和registry获得解析和注册的能力。

    其他几个实体都比较直观便于理解,不再一一赘述。

    整体交互过程

    BeanDefinitionReader是整个bean解析的聚合根,它由ApplicationContext创建,并将DefaultListableBeanFactory作为registry传递给它。
    定义解析交互过程
    BeanDefinitionReader创建文档读取实体--DocuemntReader用于加载解析,并在step3加载文档时创建上下文--ReaderContext传递给文档读取实体。上下文贯穿于整个解析过程始终,它在文档读取实体使用parser解析时也会被传入parser中。

    Parse过程是整个加载过程的核心,默认parser通过间接关联的识别器可以依据不同配置节点进行parser切换,当读到非默认配置时,则切换到对应客户化parser解析。解析完成后再通过间接关联的registry进行注册,从而配置定义进入spring管理,待getBean时使用。

    客户化配置节点解析

    客户化配置是spring非常重要的扩展点,spring强大的扩展能力有一半功能要归功于它,另一半中的80%就是后面要介绍的大名鼎鼎的BeanPostProcessor。不仅仅一些第三方扩展(例如开篇提到的dubbo)基于它,spring本身的很多模块也是基于它,例如spring-aop,spring-context等等,spring体系内除了默认的beans命名空间其余都基于它扩展的。

    NamespaceHandlerResolver由BeanDefinitionReader初始化,后者在第一次被访问时读取spring.handlers文件。.handlers文件定义namespace uri和对应处理类的映射关系。例如:

    http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
    

    上面的这行配置就是配置声明的解析类。

    NamespaceHandlerResolver依据节点namespace获得NamespaceHandler,然后使用handler处理自定义配置节点。

    public interface NamespaceHandler {
        void init();
    
        BeanDefinition parse(Element element, ParserContext parserContext);
    
        BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
    
    }
    

    init方法注册localName和自定义parser的关系,parser和localName的关系由handler的提供者自己注册。例如:

    public void init() {
            // In 2.0 XSD as well as in 2.1 XSD.
            registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
            registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
            registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
            // Only in 2.0 XSD: moved to context namespace as of 2.1
            registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        }
    

    上面就是aop注册parser的代码片段。config,aspectj-autoproxy这些就是localName,parse过程中不同的localName会切换到不同的parser解析。

    spring先通过命名空间定位到handler,handler处理时再基于localName取相应的parser解析当前结点。比如这个配置,aop是命名空间,aspectj-autoproxy是localName。整个读取解析过程中先通过aop找到AopNamespaceHandler,再在解析到aspectj-autoproxy节点时使用AspectJAutoProxyBeanDefinitionParser来解析。如果要研究spring源码,一定要先找到对应parser,知道每个配置项对应到运行时的bean结构才能更好理解spring;而且parser可能会生成一些默认的BeanPostProcessor,如果意识不到这些后处理器,那么对代码的读取将会断片,陷入完全无法理解的境地。比如spring-aop就是由parser默认生成AopAutoProxyCreator这个BeanPostProcessor,在bean初始化后由这个processor对bean生成代理。

    Bean获取

    getBean
    上图是getBean过程,整个过程很简洁,实际深入代码会发现非常繁琐。

    BeanFactory和BeanDefinitionRegistry在spring里是统一的,参见第一节,图上为了方便理解,拆成两个概念实体。

    需要注意的是第4步和第6步,bean配置时可以指定parent属性,如果有parent,则beanFactory会对local和parent做merge,merge的策略是对parent做覆盖,也可以理解为是对parent做继承。这和parent bean factory完全是两个概念,一定要区分开。

    在beans的实体静态结构里,分别注明了parent bean definition和parent bean factory。两者都是被关联的,而不是被继承。后者有点像jvm的双亲委托模型,parent和child有各自的上下文,类似于jvm的命名空间。parent bean factory由applicationContext设置,无法配置。比如spring mvc就是两个父子两个容器,在容器refresh时相应的也会把父容器的BeanFactory设置成子容器BeanFactory的parentBeanFactory。

    spring bean状态

    bean状态
    Bean主要经过instantiate,populate,initializeBean和registerDisposableBean4个状态,在状态流转中会调用很多spring预留的扩展接口。

    1. awareMethod
      如果bean继承了BeanFactoryAware,BeanNameAware,BeanClassLoaderAware,则会在initialize阶段将BeanFactory, BeanName和bean ClassLoader设置给Bean。
      注意它和ApplicationContextAware是不一样的,后者是由BeanPostProcessor做后处理set的。

    2. init method
      init method不仅仅包括配置的init-method方法还包括InitializedBean的afterPropertiesSet回调接口,这两者均是无参的,完全可以互相替代,两者中afterPropertiesSet调用在前。

    BeanPostProcessor

    上文提到过,spring另一半的扩展能力是由BeanPostProcessor提供的。先看下其接口定义

    public interface BeanPostProcessor {
        Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
        Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }
    

    两个方法分别在init-method调用前后,对bean做后处理。需要特别注意的就是postProcessAfterInitialization,大部分的spring扩展就是由它来完成的,比如上文提到的aop就是在这个阶段对bean做后处理生成代理。相应的也可以使用postProcessBeforeInitialization,但是此时init-method并未执行,后处理需要保证init-method带来的影响,@PostConstruct的方法执行就是在这个阶段。

    实例化后处理器

    InstantiationAwareBeanPostProcessor继承了BeanPostProcessor,主要用于在bean实例化前后做处理。

    public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
        Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
    
        boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
    
        PropertyValues postProcessPropertyValues(
                PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
                throws BeansException;
    }
    
    • 实例化前处理,这个方法的参数是beanClass和beanName,在bean实例化前调用,如果这个方法的返回值不为空则getBean结束,用户收到的就是这个该方法的返回值。这个扩展点主要是留给预处理的,用户可以直接生成一个同类型的bean,替换实际bean,此时实际bean不会被实例化。
    • 实例化后处理连同属性后处理是spring内部非常重要的扩展点,annotation的field注入就是在这两个阶段完成。主要有两个关键实现: CommonAnnotationBeanPostProcessor,该类在实例化后处理阶段做属性注入,主要用于@Resource AutowiredAnnotationBeanPostProcessor,该类在属性后处理阶段做属性注入,主要用于@Autowired 前者还继承了InitDestroyAnnotationBeanPostProcessor类,该类会在init-method被执行前调用@PostConstruct方法。

    原文链接

  • 相关阅读:
    HDU1720 A+B Coming
    HDU1390 ZOJ1383 Binary Numbers
    HDU1390 ZOJ1383 Binary Numbers
    HDU2504 又见GCD
    HDU2504 又见GCD
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1020 ZOJ2478 Encoding
    HDU1020 ZOJ2478 Encoding
    HDU2097 Sky数
  • 原文地址:https://www.cnblogs.com/iyulang/p/6962896.html
Copyright © 2011-2022 走看看