Spring-源码第六弹容器的始祖-DefaultListableBeanFactory

1次阅读

共计 11891 个字符,预计需要花费 30 分钟才能阅读完成。

Spring 源码持续开整!

在 XML 文件解析流程一文中,松哥和大家分享了 Spring 中配置文件的加载形式,如果小伙伴们还没看过,肯定先看一下,这有助于更好的了解本文,传送门:Spring 源码第一篇开整!配置文件是怎么加载的?。

还记得该篇文章中的代码吗?

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
System.out.println("user =" + user);

当 ClassPathResource 将文件以 IO 流的形式输入后,接下来就是结构 XmlBeanFactory,XmlBeanFactory 性能无限,它的大部分性能都在它的父类 DefaultListableBeanFactory 中实现了,而 DefaultListableBeanFactory 也相当于是容器的始祖,为什么这么说呢?咱们明天就来说一说这个话题。

本文是 Spring 源码解读第七篇,浏览本系列后面文章有助于更好的了解本文:

  1. Spring 源码解读打算
  2. Spring 源码第一篇开整!配置文件是怎么加载的?
  3. Spring 源码第二弹!XML 文件解析流程
  4. Spring 源码第三弹!EntityResolver 是个什么鬼?
  5. Spring 源码第四弹!深刻了解 BeanDefinition
  6. 手把手教你搭建 Spring 源码剖析环境

1.DefaultListableBeanFactory

要说 XmlBeanFactory 就不得不先说它的父类 DefaultListableBeanFactory,因为 XmlBeanFactory 中的大部分性能实际上在 DefaultListableBeanFactory 中就曾经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已。

DefaultListableBeanFactory 是一个残缺的、性能成熟的 IoC 容器,如果你的需要很简略,甚至能够间接应用 DefaultListableBeanFactory,如果你的需要比较复杂,那么通过扩大 DefaultListableBeanFactory 的性能也能够达到,能够说 DefaultListableBeanFactory 是整个 Spring IoC 容器的始祖。

咱们先来看一下 DefaultListableBeanFactory 的继承关系:

从这张类的关系图中能够看出,DefaultListableBeanFactory 实际上也是一个集大成者。在 Spring 中,针对 Bean 的不同操作都有不同的接口进行标准,每个接口都有本人对应的实现,最终在 DefaultListableBeanFactory 中将所有的实现汇聚到一起。从这张类的继承关系图中咱们大略就能感触到 Spring 中对于类的设计是如许厉害,代码耦合度非常低。

这些类,在本系列前面的介绍中,大部分都会波及到,当初我先大略介绍一下每个类的作用,大家先混个脸熟:

  1. BeanFactory:这个接口看名字就晓得是一个 Bean 的工厂,BeanFactory 接口定义了各种获取 Bean 的办法、判断 Bean 是否存在、判断 Bean 是否单例等针对 Bean 的根底办法。
  2. ListableBeanFactory:这个接口继承自 BeanFactory,在 BeanFactory 的根底上,扩大了 Bean 的查询方法,例如依据类型获取 BeanNames、依据注解获取 BeanNames、依据 Bean 获取注解等。
  3. AutowireCapableBeanFactory:该接口继承自 BeanFactory,在 BeanFactory 的根底上,提供了 Bean 的创立、配置、注入、销毁等操作。有时候咱们须要本人手动注入 Bean 的时候,能够思考通过实现该接口来实现。AutowireCapableBeanFactory 在 Spring Security 中有一个重要的利用就是 ObjectPostProcessor,这个松哥将在 Spring Security 系列 %26version%3D12031f10%26nettype%3DWIFI%26lang%3Den%26fontScale%3D100%26exportkey%3DA7Vh2vnoyPfiNe4xJBp1Abg%253D%26pass_ticket%3DcsesYv%252BwBmhWaBHD26d%252FJ7tMkuXP0dO73h0sw2UG8l0e1hhkKGiIMjql0rJcXL0r%26winzoom%3D1.000000&uin=&key=&devicetype=iMac+MacBookPro15%2C1+OSX+OSX+10.13.6+build(17G2208)&version=12031f10&lang=en&nettype=WIFI&ascene=0&fontScale=100&winzoom=1.000000) 中和大家具体介绍。
  4. HierarchicalBeanFactory:该接口继承自 BeanFactory,并在 BeanFactory 根底上增加了获取 parent beanfactory 的办法。
  5. SingletonBeanRegistry:这个接口定义了对单例 Bean 的定义以及获取办法。
  6. ConfigurableBeanFactory:这个接口次要定了针对 BeanFactory 的各种配置以及销毁的办法。
  7. ConfigurableListableBeanFactory:这是 BeanFactory 的配置清单,这里定义了疏忽的类型、接口,通过 Bean 的名称获取 BeanDefinition、解冻 BeanDefinition 等。
  8. AliasRegistry:这个接口定义了对 alias 的注册、移除、判断以及查问操作。
  9. SimpleAliasRegistry:这个类实现了 AliasRegistry 接口并实现了它里边的办法,SimpleAliasRegistry 应用 ConcurrentHashMap 做载体,实现了对 alias 的注册、移除判断以及查问操作。
  10. DefaultSingletonBeanRegistry:这个类基于 Java 中的汇合,对 SingletonBeanRegistry 接口进行了实现。
  11. FactoryBeanRegistrySupport:该类继承自 DefaultSingletonBeanRegistry,并在 DefaultSingletonBeanRegistry 的根底上,减少了获取 FactoryBean 类型、移除 FactoryBean 缓存的办法等等操作。
  12. AbstractBeanFactory:实现了 ConfigurableBeanFactory 接口并继承自 FactoryBeanRegistrySupport,在 AbstractBeanFactory 中对 ConfigurableBeanFactory 中定义的办法进行了实现。
  13. AbstractAutowireCapableBeanFactory:该类继承自 AbstractBeanFactory 并对 AutowireCapableBeanFactory 接口中定义的办法进行了落地实现。
  14. BeanDefinitionRegistry:这个接口继承自 AliasRegistry 接口,并减少了一系列针对 BeanDefinition 的注册、移除、查问、判断等办法。
  15. 最初的 DefaultListableBeanFactory 天然就具备了下面所有的性能。

下面的内容可能看的大家目迷五色,松哥这里通过几个简略理论的例子,来带大家应用一下 DefaultListableBeanFactory 的性能,可能大家的了解就比拟清晰了。

DefaultListableBeanFactory 作为一个集大成者,提供了十分多的性能,咱们一个一个来看。

2. 代码革新

首先文章中一开始的三行代码咱们能够对其略加革新,因为咱们曾经说了 XmlBeanFactory 中的大部分性能实际上在 DefaultListableBeanFactory 中就曾经提供好了,XmlBeanFactory 只是对 IO 流的读取做了一些定制而已,文件的读取次要是通过 XmlBeanDefinitionReader 来实现的(本系列后面文章曾经讲过),咱们能够对文章一开始的三行代码进行革新,以便更好的体现“XmlBeanFactory 中的大部分性能实际上在 DefaultListableBeanFactory 中就曾经提供好了”:

ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
User user = factory.getBean(User.class);
System.out.println("user =" + user);

应用前四行代码代替 XmlBeanFactory,这样 XmlBeanFactory 的性能是不是就很明确了?就是前四行代码的性能。

3. 动静注册 Bean

动静注册 Bean,这是 DefaultListableBeanFactory 的性能之一,不过精确来说应该是动静注册 BeanDefinition。

咱们先来看一个简略的例子:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user =" + user);

首先咱们本人手动构建一个 DefaultListableBeanFactory 对象。当然也能够应用后面的 XmlBeanFactory。

而后再手动构建一个 GenericBeanDefinition。在后面的文章中,松哥和大家讲过,当初默认应用的 BeanDefinition 就是 GenericBeanDefinition,所以这里咱们本人也手动构建一个 GenericBeanDefinition。有了 GenericBeanDefinition 之后,咱们设置相干的类和属性。

接下来再将 userBeanDefinition 注册到 defaultListableBeanFactory。注册实现之后,咱们就能够从 defaultListableBeanFactory 中获取相应的 Bean 了。

这里说一句题外话,心愿大家在浏览本系列每一篇文章的时候,可能将本系列前后文章分割起来一起了解,这样会有很多意料之外的播种。例如下面的,咱们既能够申明一个 DefaultListableBeanFactory,也能够申明一个 XmlBeanFactory,那你大略就能据此推断出 XmlBeanFactory 的次要目标可能就是对资源文件进行读取和注册。

那么到底是怎么注册的呢?咱们来看一下 defaultListableBeanFactory.registerBeanDefinition 办法的定义:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {((AbstractBeanDefinition) beanDefinition).validate();}
        catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean'" + beanName +
                        "'with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean'" + beanName +
                        "'with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        else {if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean'" + beanName +
                        "'with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {clearByTypeCache();
    }
}

registerBeanDefinition 办法是在 BeanDefinitionRegistry 接口中申明的,DefaultListableBeanFactory 类实现了 BeanDefinitionRegistry 接口,并实现了该办法,咱们来看剖析下该办法:

  1. 首先对传入的 beanDefinition 对象进行校验,这也是注册前的最初一次校验,不过这个时候 BeanDefinition 对象曾经到手了,所以这个校验并非 XML 文件校验,这里次要是对 methodOverrides 的校验。
  2. 接下来会依据 beanName 从 beanDefinitionMap 中获取 BeanDefinition,看看以后 Bean 是否曾经定义过了。beanDefinitionMap 是一个 Map 汇合,这个汇合中 key 是 beanName,value 是 BeanDefinition 对象。
  3. 如果 BeanDefinition 曾经存在了,那么接下来会判断是否容许 BeanDefinition 笼罩,如果不容许,就间接抛出异样(不晓得小伙伴们有没有印象,在松哥后面的 OAuth2 系列教程中,常常须要配置容许 BeanDefinition 的笼罩,就是因为这个起因,公众号【江南一点雨】后盾回复 OAuth2 获取该教程),如果容许 BeanDefinition 的笼罩,那就向 beanDefinitionMap 中再次存一次值,笼罩之前的值。
  4. 如果 BeanDefinition 不存在,那就间接注册。间接注册分两种状况:我的项目曾经运行了和我的项目还没运行。
  5. 如果我的项目曾经运行,因为 beanDefinitionMap 是一个全局变量,可能存在并发问题,所以要加锁解决。否则就间接注册,所谓的注册就是把对象存入 beanDefinitionMap 中,同时将 beanName 都存入 beanDefinitionNames 汇合中。

这便是 registerBeanDefinition 办法的工作流程。

有小伙伴会说,这个办法从头到尾都是 BeanDefinition,跟 Bean 有什么关系呢?

咋一看的确如同和 Bean 没有间接关系。

其实这波及到另外一个问题,就是 Bean 的懒加载。这个时候先把 BeanDefinition 定义好,等到真正调用 Bean 的时候,才会去初始化 Bean。咱们能够在 User 类的构造方法中打印日志看下,如下:

public class User {
    private String username;
    private String address;

    public User() {System.out.println("--------user init--------");
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public String getUsername() {return username;}

    public void setUsername(String username) {this.username = username;}

    public String getAddress() {return address;}

    public void setAddress(String address) {this.address = address;}
}

从下图能够看到,当 BeanDefinition 注册实现后,User 并没有初始化,等到 getBean 办法被调用的时候,User 才初始化了。

须要留神的是,咱们日常开发中应用的 ApplicationContext 并非懒加载,这个在松哥的 Spring 入门视频中能够看到成果【https://www.bilibili.com/video/BV1Wv41167TU】,具体原理松哥将在本系列前面的文章中和大家分享。

那么如果不想懒加载该怎么办呢?当然有方法。

4. 提前注册 Bean

在 DefaultListableBeanFactory 中还有一个 preInstantiateSingletons 办法能够提前注册 Bean,该办法是在 ConfigurableListableBeanFactory 接口中申明的,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口并实现了接口中的办法:

@Override
public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in" + this);
    }
    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                        ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {getBean(beanName);
                    }
                }
            }
            else {getBean(beanName);
            }
        }
    }
    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

preInstantiateSingletons 办法的整体逻辑比较简单,就是遍历 beanNames,对符合条件的 Bean 进行实例化,而且大家留神,这里所谓的提前初始化其实就是在咱们调用 getBean 办法之前,它本人先调用了一下 getBean。

咱们能够在案例中手动调用该办法:

DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("username", "javaboy");
pvs.add("address", "www.javaboy.org");
userBeanDefinition.setPropertyValues(pvs);
userBeanDefinition.setBeanClass(User.class);
defaultListableBeanFactory.registerBeanDefinition("user", userBeanDefinition);
defaultListableBeanFactory.preInstantiateSingletons();
User user = defaultListableBeanFactory.getBean(User.class);
System.out.println("user =" + user);

此时在调用 getBean 办法之前,User 就曾经初始化了,如下图:

5.getBean

DefaultListableBeanFactory 中另外一个重量级办法就是 getBean 了。不过 getBean 办法的真正实现是在 DefaultListableBeanFactory 的父类 AbstractBeanFactory 中,具体的实现办法是 doGetBean,原本想和大家子在这里聊一聊这个问题,然而发现这是一个十分宏大的问题,BeanFactory 和 FactoryBean 都还没和大家分享,所以这个话题咱们还是暂且押后,一个点一个点来。

6. 小结

好啦,明天就先说这么多,每篇源码我都尽量配置套一些小案例来演示,这样防止大家看的太干燥了,咱们下周持续~

如果大家感觉有播种,记得点个在看激励下松哥哦~

正文完
 0