spring源码深入解析BeanFactory

本文深入探讨了BeanFactory,它是Spring核心容器的一部分,负责控制反转和依赖注入。介绍了DefaultSingletonBeanRegistry中的singletonObjects如何存储单例对象,并对比了ApplicationContext与BeanFactory的区别,包括ApplicationContext在资源处理和事件发送上的额外功能。此外,详细阐述了BeanFactory的实现方式,如registerBeanDefinition和BeanFactoryPostProcessor,以及Spring的懒加载机制。最后讨论了BeanFactory与ApplicationContext在处理Bean后处理器和属性占位符解析的差异,并指出在@Autowired和@Resource注解共存时的处理顺序。
  1. 什么是BeanFactory

    是ApplicationContext的父接口

    Spring的核心容器,主要的ApplicationContext实现(或者组合)了它的功能

    在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WApTu30A-1657012593065)(https://secure2.wostatic.cn/static/6BAL5Dn9e6jCErS9EVMbUj/image.png)]

单例的bean存储在singletonObjects中
  1. BeanFactory的作用

    控制反转,基本的依赖注入,直至Bean的生命周期的各种功能,都有它实现
    在这里插入图片描述

    DefaultSingletonBeanRegistry中的singletonObjects存放了单例的对象

    查看singletonObjects中的存储内容

  private void getSingletonObjects(AnnotationConfigWebApplicationContext context) {
    try {
      Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
      singletonObjects.setAccessible(true);
      BeanFactory parentBeanFactory = context.getBeanFactory();
      Object o = singletonObjects.get(parentBeanFactory);
      System.out.println(o);
//      Map<String, Object> map= (Map<String, Object>)singletonObjects.get(parentBeanFactory);
//      map.forEach((k,v)->{
//        System.out.println(k + "=" + v);
//      });

    } catch (Exception e){
      e.printStackTrace();

    }


  }
  1. ApplicationContext与BeanFactory的区别?

    从上面的类图中可以发现ApplicationContext还集成了资源处理类,获取配置信息,还可发送事件

private void getResource(AnnotationConfigWebApplicationContext context) {
    try {
      Resource[] resources = context.getResources("classpath:application.properties");
      for (Resource resource : resources) {
        System.out.println(resource);

      }
      System.out.println(context.getEnvironment().getProperty("java_home"));
      System.out.println(context.getEnvironment().getProperty("server.port"));
      //容器之间使用
      context.publishEvent(new UserRegisterEvent(context));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
任一spring组件都可一处理发布时的事务。**观察者模式**

在这里插入图片描述

  1. BeanFactory的实现

    BeanFactory可以使用registerBeanDefinition进行获取bean的定义。使用后处理器BeanFactoryPostProcessor进行对BeanFactory的扩展,补充bean的定义

public class TestBeanFactory {
  public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    //bean的定义(class,scope,初始化,销毁)
    //先获取对象定义的关信息
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();
    //打bean定义放在beanFactory中
    beanFactory.registerBeanDefinition("config",beanDefinition);
    String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
    //打印beanFactory中的bean定义名字,获取beanFactory中的此时只会打印config。使用@bean注解的类并没有生效
    //beanFactory并没有处理注解的能力
    for (String beanDefinitionName : beanDefinitionNames) {
      System.out.println(beanDefinitionName);
    }
    System.out.println("---------------------------------------------------------------------------");

    //给beanFactory添加常用的后处理器,后处理器进行beanFactory的扩展
    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    String[] beanDefinitionNameArray = beanFactory.getBeanDefinitionNames();
    //此时打印的是spring内置的处理器,Bean1对象不在容器中
    for (String beanDefinitionName : beanDefinitionNameArray) {
      System.out.println(beanDefinitionName);
    }
    System.out.println("---------------------------------------------------------------------------");

    //拿到符合类型的所有后处理器,使用处理器进行解析
    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(item->{
      item.postProcessBeanFactory(beanFactory);
    });
    String[] beanDefinitionNameArrays = beanFactory.getBeanDefinitionNames();
    //此时打印的是spring内置的处理器,Bean1对象不在容器中
    for (String beanDefinitionName : beanDefinitionNameArrays) {
      System.out.println(beanDefinitionName);
    }
    System.out.println("---------------------------------------------------------------------------");

  }

  @Configuration
  static class Config{
    @Bean
    public Bean1 bean1(){
      return new Bean1();
    }

    @Bean
    public Bean2 bean2(){
      return new Bean2();
    }

  }


  static class Bean1{
    @Autowired
    private Bean2 bean2;

    public Bean1() {
      System.out.println("bean1");

    }
  }

  static class Bean2{

    public Bean2() {
      System.out.println("bean2");

    }

  }
}

运行结果如下
在这里插入图片描述spring使用懒加载。当对象使用时才会创建。调用beanFactory.preInstantiateSingletons();会预先加载单例对象

//    //获取bean1对象
//    Bean2 bean2 = beanFactory.getBean(Bean1.class).getBean2();
//    System.out.println(bean2);
//    //此时打印bean2为空,证明@Autowired注解未启用,可以使用bean 后处理器进行解决
//    System.out.println("---------------------------------------------------------------------------");

    //bean 后处理器 和 beanFactory 后处理器作用不同,针对bean声明周期的各个阶段提供扩展如:@Autowired
    beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
    Bean2 bean22 = beanFactory.getBean(Bean1.class).getBean2();
    System.out.println(bean22);
    System.out.println("---------------------------------------------------------------------------");

在这里插入图片描述

beanFactory不会主动做的事情,

  • 不会主动添加BeanFactory 后处理器
  • 不会主动添加Bean 后处理器,bean后处理器会有排序的逻辑
  • 不会主动初始化单例
  • 不会解析${ }和#{}

但ApplicationContext已经做好了这些解析

如果@Autowired和@Resource同时在一个对象变量使用时,@Autowired先生效。查看AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory)源码可以发现;

bean后处理器有排序逻辑

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pp1KoOcS-1657013058914)(https://secure2.wostatic.cn/static/pqK8FBZ88BeE7Z9m8r8TCz/image.png)]

如果想要改变顺序可以添加比较器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值