• BeanFactory 和 ApplicationContext


    从一个示例开始,先自定义一个类:

    package top.callback.demo.bean;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.context.ApplicationContext;
    
    public class User {
      private BeanFactory beanFactory;
      private ObjectFactory<ApplicationContext> objectFactory;
      
      // getter & setter
    }
    

    配置文件:

    <bean id="user" class="top.callback.demo.bean.User" autowire="byType" />
    

    测试程序:

    public static void main(String[] args) {
      BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/application-context.xml");
      User user = beanFactory.getBean(User.class);
      BeanFactory innerBeanFactory = user.getBeanFactory();
      ObjectFactory<ApplicationContext> applicationContext = user.getObjectFactory().getObject();
      
      System.out.println(beanFactory == innerBeanFactory); // false
      System.out.println(beanFactory == applicationContext); // true
    }
    

    为什么 beanFactory 不等于 innerBeanFactory,而等于 applicationContext

    按理说,User 对象是从 beanFactory 获取的,那么 user#beanFactory 和 beanFactory 应该是一个东西,但实际上却是爹生了娃,但亲子鉴定说娃不是亲生的。这时候就要从 ClassPathXmlApplicationContext 入手,去看看他的继承关系是什么样的。

    如果图片看不清楚,可以自行在 IDEA 里面借助 Diagrms 功能进行查看。从图中可以看到,ClassPathXmlApplicationContext 一路火花带闪电的层层继承,最终成为了 BeanFactory 接口的一个间接实现。所以代码里可以使用多态将 ClassPathXmlApplicationContext 的实例赋值给 BeanFactory。

    在继承链中有一个抽象类 AbstractApplicationContext,其中重载了多个 getBean() 方法用于获取容器内的 Bean。而这些方法无一例外的都调用了 getBeanFactory() 来先获取一个 BeanFactory 实例,进而调用 BeanFactory 的 getBean() 方法实际执行 Bean 获取。

    意外的是,这个类里的 getBeanFactory() 方法是个抽象方法。查看其返回值 ConfigurableListableBeanFactory 接口的实现,发现无论哪个实现都是返回自身的 beanFactory 字段,而这个字段的类型都是 DefaultListableBeanFactory。

    同时,在 AbstractApplicationContext 的 prepareBeanFactory() 中也明确指定了要使用的 BeanFactory 实现是通过 getBeanFactory() 方法返回的 DefaultListableBeanFactory。

    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); // AbstractApplicationContext 663行
    

    回到最初的示例,配置文件里指定了以 byType 类型注入的形式进行注入,那么根据上述分析,user#beanFactory 注入的就一定是 DefaultListableBeanFactory。而通过配置文件创建的是 ClassPathXmlApplicationContext 的实例,这两个对象自然就不相等了。

    至于示例中的 beanFactory 等于 applicationContext,这是因为在这个示例程序运行过程中,只有一个 ClassPathXmlApplicationContext 是 ApplicationContext 接口的实现,所以按类型注入下两者其实就是同一个对象。

    结合上面的继承关系图可以看出,ClassPathXmlApplicationContext 实际上是 BeanFactory 接口的一个最终实现。在其继承链上,BeanFactory 被从 ApplicationContext 接口开始的多个类进行了功能丰富,并且对 BeanFactory 的基础功能进行了代理。官方文档这么描述 BeanFactory 和 ApplicationContext 的关系:

    In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container.

    ApplicationContext 是 BeanFactory 的超集,BeanFactory 仅提供基础功能和配置,ApplicationContext 在其上面增加了更多企业性功能。可以简单的理解为,BeanFactory 是给 Spring 框架自身用的,而 ApplicationContext 是给 Spring 框架的使用者用的。

  • 相关阅读:
    v-model
    CSS background 属性
    渐变背景
    mint ui的field用法和修改样式的方法
    js 数组包含
    password 密码查询
    web 单一平台登录逻辑
    内存共享锁业务逻辑(原创)
    无限分类树操作
    根据日期获取,x岁x月x天
  • 原文地址:https://www.cnblogs.com/zidu/p/spring-beanfactory-application-context.html
Copyright © 2020-2023  润新知