zoukankan      html  css  js  c++  java
  • Spring源码解析

    我们先来看类图吧:

    除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口.

    这边主要提供了这样的三个功能: 别名管理,单例创建与注册,工厂方法FactoryBean支持.

    我们来看看这些接口,类的主要职责吧:

    BeanFactory Spring IOC容器的根接口

    -- HierachicalBeanFactory 实现容器的继承,就是可以有父 BeanFactory

    -- -- ConfigureabelBeanFactory 提供factory的配置功能

    AliasRegistry 定义bean name的别名管理

    -- SimpleAliasRegistry 在实现别名管理接口基础上,添加一个canonicalName查找类真是名称api

    SingletonBeanRegistry 提供单例注册,查询服务

    -- DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)

    -- -- FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持

    -- -- -- AbstractBeanFactory BeanFactory的抽象实现.

    也就是说这边可以分为这样几类职责:

    a, 类别名管理

    b, 单例生命周期管理

    c, 工厂方法初始化类对应的FactoryBean

    d, BeanFactory容器

    BeanFactory容器的职责(BeanFactory,HierachicalBeanFactory,ConfigureableBeanFactory)在上一篇文章<Spring源码解析 - BeanFactory接口体系解读>里已经分析过,有兴趣可以看下.

    我们今天主要分析其他的三个职责,如下的接口与类(顺便做目录):

    1. AliasRegistry 定义bean name的别名管理

    2. SimpleAliasRegistry 实现别名管理接口

    3. SingletonBeanRegistry 提供单例注册,查询服务

    4. DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)

    5. FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持

    1. AliasRegistry 定义bean name的别名管理

    提供别名的注册,查找,删除,判断定义.

     看个类图就行,不用展开.

    2. SimpleAliasRegistry 实现别名管理接口

    这边除了实现接口定义的api,还添加了两个公共api:

      批量校验别名public void resolveAliases(StringValueResolver valueResolver)和查找别名对应的原始类名public String canonicalName(String name)

    这边以别名为key缓存数据.

    1     /** Map from alias to canonical name */
    2     private final Map<String, String> aliasMap = new ConcurrentHashMap<String, String>(16);

    分析下api实现逻辑吧:

    2.1 别名注册 registerAlias(String name, String alias)

    2.2 删除别名public void removeAlias(String alias)

      校验下,如果别名不存在报错:throw new IllegalStateException("No alias '" + alias + "' registered");

    2.3 判断别名是否存在

      直接使用ConcurrentHashMap的containsKey

    2.4 获取别名public String[] getAliases(String name)

      主要逻辑是加了个锁,然后是递归调用retrieveAliases,查找多层次的别名(就是查找别名的别名这些下去)

    2.5 使用StringValueResolver解析类名,别名后,进行循环依赖的校验

      这边使用的是StringValueResolver的接口,具体实现需要靠注入

    3. SingletonBeanRegistry 提供单例注册,查询服务

    这边定义的单例注册,有点门道,主要就是相对BeanFactory的api而言有点low,没有做附加的处理.

      注册的时候不管注入afterPropertiesSet的初始化回调.

      查找的时候不管还没初始化的单例不说,还不管别名问题,不管FactoryBean如何区分是获取FactoryBean本身还是getObject初始化的实例.

    咱们一个个api分析吧.

    3.1 注册单例 void registerSingleton(String beanName, Object singletonObject);

      这边的实现不会再调用 初始化回调函数,如InitializingBean 的afterPropertiesSet,所以这边应该接收的是完成初始化的实例

      同理也不会调用销毁的回调,如DisposableBean的destroy

      这跟标准的BeanFactory中注册单例是明显不同的,因为那边是会调用各种回调.

    3.2 查找单例 Object getSingleton(String beanName); 

          String[] getSingletonNames();

          int getSingletonCount();

      设计于访问手动注册的单例.

      这边只会查找已经初始化完毕 的单例,有bean definition但没有实例化的这边查找不到.

      这边也不会处理FactoryBean的情况(就是具体获取getObject还是factoryBean本身的区分,&),别名也需要预先转化好了来查.

    3.3 判断是否保护单例 boolean containsSingleton(String beanName);

      只有单例已经实例化才会返回true,剩下的看3.2 查找单例的说明吧,一样的.

    4. DefaultSingletonBeanRegistry 实现单例与DisposableBean的生命周期管理(创建,维护,销毁)

     在SingletonBeanRegistry注册的基础上,添加单例的共享.

    也支持容器关闭时,DisposableBean实例的销毁

    4.1 这边注册时,通过下面四个变量来维护:

      Map<String, Object> singletonObjects 缓存以bean name为key的单例实例

      Map<String, ObjectFactory> singletonFactories 缓存以bean name 为key的ObjectFactory

      Map<String, Object> earlySingletonObjects 用于解决单例时的循环依赖,这边缓存以bean name为key的预初始化单例

      Set<String> registeredSingletons 已经注册好的单例bean name

      这边singletonObjects和registeredSingletons的数据应该是同步的,只是适用于不同的场景,但他们俩跟singletonFactories 和earlySingletonObjects分别互斥,就是singletonObjects里有了,这两个肯定没有.

      

      同时这边也有inCreationCheckExclusions和singletonsCurrentlyInCreation进行锁控制的概念.

        singletonsCurrentlyInCreation缓存bean正在被初始化,这样就不能再发起初始化;

        inCreationCheckExclusions 直接缓存当前不能加载的bean

      这部分看个例子就,清晰了,初始化前需要先使用beforeSingletonCreation判断

        这边inCreationCheckExclusions不包含beanName才会去判断singletonsCurrentlyInCreation

    1     protected void beforeSingletonCreation(String beanName) {
    2         if (!this.inCreationCheckExclusions.containsKey(beanName) &&
    3                 this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
    4             throw new BeanCurrentlyInCreationException(beanName);
    5         }
    6     }

    4.2 管理bean的依赖问题

      使用如下三个属性进行管理:

      Map<String, Set<String>> containedBeanMap  依赖的bean name为key , 就是依赖类 -> 查找 被依赖的类

      Map<String, Set<String>> dependentBeanMap  依赖的原始bean name为key

      Map<String, Set<String>> dependenciesForBeanMap  被依赖的bean name为key

    4.3 bean 销毁

      这不过跟初始化类似,自行看代码比较简单.    

    5. FactoryBeanRegistrySupport 添加工厂方式创建类FactoryBean的支持

    添加对FactoryBean的支持,就是使用工厂方法初始化类.

    这里主要涉及3个新概念:FactoryBean,BeanPostProcessor和AccessController.这三个概念懂了,源码也就分析完了.

    5.1 FactoryBean,通过T getObject() api提供简单工厂方法,可用用于创建单例,原型模式的实例.主要用于创建过程复杂,xml配置不方便的情况.

      其实这个就是使用spring的接口对简单工厂设计模式做了一个规范,方便大家在spring中配置使用.

      具体直接看<Spring配置bean的方法(工厂方法和Factorybean)>

    5.2 BeanPostProcessor用于bean 初始化时进行功能增强,类似web开发中的filter.

      这边有两个api:

      postProcessBeforeInitialization 在类初始化前调用,比InitializaingBean 的 setPropertiesSet 和 xml文件中自定义的init-method方法执行都早

      postProcessAfterInitialization 类初始话后调用,在InitializaingBean 的 setPropertiesSet 和 xml文件中自定义的init-method方法之后执行

    5.3 AccessController jdk的安全控制,跟spring关联不大,还是度娘吧,不多写了.

      在 Java 中将执行程序分成本地和远程两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。

      在应用开发中还有一些关于安全的复杂用法,其中最常用到的 API 就是 doPrivileged。doPrivileged 方法能够使一段受信任代码获得更大的权限,甚至比调用它的应用程序还要多,可做到临时访问更多的资源。

    所以就出现了spring中的典型代码

     1 if (System.getSecurityManager() != null) {
     2     AccessControlContext acc = getAccessControlContext();
     3     try {
     4         object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
     5             public Object run() throws Exception {
     6                     return factory.getObject();
     7                 }
     8             }, acc);
     9     }
    10     catch (PrivilegedActionException pae) {
    11         throw pae.getException();
    12     }
    13 }else {
    14     object = factory.getObject();
    15 }
  • 相关阅读:
    【转】 IntelliJ IDEA 详细图解最常用的配置 ,适合刚刚用的新人
    安装IntelliJ IDEA默认C盘文件过大怎么办
    [linux]netstat命令详解-显示linux中各种网络相关信息
    [linux]free命令详解-显示内存的使用情况
    用什么工具能找出性能瓶颈?
    [linux]iostat命令详解-监视系统输入输出设备和CPU的使用情况
    [linux]vmstat命令详解-显示虚拟内存状态
    好文章列表
    BigDecimal.setScale 处理java小数点
    Mybatis通用分页
  • 原文地址:https://www.cnblogs.com/leftthen/p/5265640.html
Copyright © 2011-2022 走看看