8、初识高级工厂ApplicationContext

前言

前面的对象创建的整体流程我们已经学完了,那么接下来我们该学一学高级工厂ApplicationContext的用法了。

Spring的核心容器DefaultListableBeanFactory类

spring的核心容器:DefaultListableBeanFactory。

类图:

继承的两大体系:

  1. BeanFactory :bean工厂体系,获得了工厂所具有的功能。
    1. 查找对象
    2. 创建对象
  2. AliasRegistry + SingletonBeanRegistry:注册器的体系,获得了注册(存储)的功能。存储的地方有如下:
    1. BeanDefinitionMap:存储BeanDefinition的map
    2. SingletonObjects:单例池
    3. EarlySingleObjects:早期的单例池
    4. SingletonFactories:单例工厂池

ApplicationContext工厂

ApplicationContext也叫做应用的上下文,或者应用的环境。

在咱们开发的过程中,基本上使用的是这个工厂,因为这个工厂和Spring的核心容器 DefaultListableBeanFactory 功能类似,下面咱们要探讨问题如下:

  1. ApplicationContext 和 DefaultListableBeanFactory 有什么关系。
  2. 为什么在开发过程中要使用 ApplicationContext 工厂

ApplicationContext类图:

ApplicationContext的能力:

从上图我们可以知道,ApplicationContext 是 BeanFactory 的子接口,所以ApplicationContext 也具有 BeanFactory 的能力。

而作为子类的ApplicationContext 显然会具有比父类 BeanFactory 更多的功能。扩展点如下:

  1. EnvironmentCapable:具有环境感知的能力。配置文件中可以配置profile标签,分别可以配置dev(开发环境),product(产品环境,线上环境)
  2. ListableBeanFactory:这个工厂内部提供了一些方法,能更方便的展示bean的信息,对bean进行判断。
  3. HierarchicalBeanFactory:具有父子容器的能力。
  4. MessageSource:处理消息的能力,与事件发布是一对,一个发布,一个接收。
  5. ApplicationEventPublisher:事件发布的功能。
  6. ResourcePatternResolver:处理资源更加方便。例如:xml,Configuration配置类。
  7. BeanFactory:查找对象,创建对象。

但是从目前来看ApplicationContext扩展了这么多的能力,但是却比DefaultListableBeanFactory少了registry(注册)的能力,而没有registry的能力ApplicationContext就无法存储这些bean的信息。ApplicationContext并没有继承任何registry的接口,那么spring是怎么让ApplicationContext具有注册的能力的呢?

Spring中如果A类如果想拥有B类的能力,有两种方式可以使用:

  1. 通过继承的方式:A类继承B类。
  2. 通过成员变量的方式:A类中设置一个B类型的成员变量,然后将B类注入进A类。

因为单继承的原因,Spring这里使用的是通过成员变量的方式进行的。

所以大家思维发散一下。DefaultListableBeanFactory有registry的能力,ApplicationContext如果想拥有这个能力,是不是可以在ApplicationContext中缓存一个DefaultListableBeanFactory类型的成员变量呢。

很显然Spring就是这么做的。大家可以找到ApplicationContext接口,这个接口并没有直接存储DefaultListableBeanFactory,而是ApplicationContext接口的实现类所继承的类存储起来的。下面举个例子:

通过这个类图可以知道,ClassPathXmlApplicationContext是ApplicationContext的一个子实现,而通过继承以及实现的关系,这个子实现继承了AbstractRefreshableApplicationContext,而这个类就存储了DefaultListableBeanFactory。

看一下AbstractRefreshableApplicationContext这个类的源码:

里面清晰的能看到有个成员变量DefaultListableBeanFactory。

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Nullable
    private Boolean allowBeanDefinitionOverriding;
    @Nullable
    private Boolean allowCircularReferences;
    @Nullable
    private volatile DefaultListableBeanFactory beanFactory;

    public AbstractRefreshableApplicationContext() {
    }

    public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
        super(parent);
    }

    public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
        this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
    }

    public void setAllowCircularReferences(boolean allowCircularReferences) {
        this.allowCircularReferences = allowCircularReferences;
    }

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

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException var2) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
        }
    }

    protected void cancelRefresh(BeansException ex) {
        DefaultListableBeanFactory beanFactory = this.beanFactory;
        if (beanFactory != null) {
            beanFactory.setSerializationId((String)null);
        }

        super.cancelRefresh(ex);
    }

    protected final void closeBeanFactory() {
        DefaultListableBeanFactory beanFactory = this.beanFactory;
        if (beanFactory != null) {
            beanFactory.setSerializationId((String)null);
            this.beanFactory = null;
        }

    }

    protected final boolean hasBeanFactory() {
        return this.beanFactory != null;
    }

    public final ConfigurableListableBeanFactory getBeanFactory() {
        DefaultListableBeanFactory beanFactory = this.beanFactory;
        if (beanFactory == null) {
            throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
        } else {
            return beanFactory;
        }
    }

    protected void assertBeanFactoryActive() {
    }

    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
    }

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }

        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }

    }

    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory var1) throws BeansException, IOException;
}

基于上面这些能力的扩展,所以我们开发过程中会使用 ApplicationContext 工厂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值