第二讲:BeanFactory的实现

Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考

  • DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转依赖注入功能,都是它来实现
  • ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
  • FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
  • XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
  • AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
  • AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
  • AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
  • AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)

另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来。


1. 环境准备

在开始之前,先准备如下代码:

/**
 * 测试BeanFactory的实现类
 *
 * @Date 2023/8/20 15:20
 */
@Slf4j
public class FactoryImplApplication {

    public static void main(String[] args) {
		// TODO
    }

    @Configuration
    static class Config{

        @Bean
        public Component01 bean1() {
            return new Component01();
        }

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

    static class Component01 {

    @Resource
    private Component02 bean02;

    public Component01() {
        System.out.println("Component01构造器~~~");
    }

    public Component02 getBean02() {
        return bean02;
    }
}

    static class Component02 {

        public Component02() {
            System.out.println("Component02构造器~~~");
        }
    }
}


BeanDefinition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等

2. 初始化DefaultListableBeanFactory

// 仅创建BeanFactory,并没有创建ApplicationContext,此时打印容器中的BeanDefinition个数,一个都没有。
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
log.info("仅创建beanFactory时,不会自动创建其他的BeanDefinition,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());

在这里插入图片描述

3. 手动注册BeanDefinition

手动创建Config.class的BeanDefinition并注册到BeanFactory中。

AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
        .setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", configBeanDefinition);
log.info("向BeanFactory手动注册一个BeanDefinition,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());

在这里插入图片描述


4. 手动添加后置处理器

学过Spring的应该都知道,Config类上@Configuration,并且里面的方法上有@Bean,那么这个方法的返回对象应该也会被注入容器中。但这边为什么没有呢?这是因为@Configuration并没有被解析,它是由BeanFactory后置处理器来处理的(ConfigurationClassPostProcessor)。主要功能是补充了一些BeanDefinition。

接着,我们给它添加一些常用的后置处理器并调用postProcessBeanFactory(),重新打印日志。

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
log.info("向BeanFactory添加一些常用的BeanFactory后置处理器后,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).forEach((key, value) -> {
    // 调用BeanFactory后置处理器
    value.postProcessBeanFactory(beanFactory);
});

Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);

在这里插入图片描述

此时,BeanFactory中就有我们需要的BeanDefinition了。

注意:这几个后置处理器非常重要!!!下面会用得到!!!
注意:这几个后置处理器非常重要!!!下面会用得到!!!
注意:这几个后置处理器非常重要!!!下面会用得到!!!


BeanFactory后置处理器:补充BeanDefinition
Bean后置处理器:针对Bean的生命周期的各个阶段提供扩展,例如解析@Autowired、@Resource等

5. 获取被依赖注入的Bean对象

有了BeanDefinition之后,就可以获取Bean了。但BeanFactory不会主动创建Bean,调用getBean()的时候才会被创建。

我们试着获取bean01:

Component01 bean01 = beanFactory.getBean(Component01.class);
System.out.println("从容器中获取的bean01:" + bean01);
System.out.println("被依赖注入的bean02:" + bean01.getBean02());

运行结果:

在这里插入图片描述

bean01被成功创建,但是bean02好像并没有被依赖注入???
这是因为创建bean01之后,beanFactory并不会主动依赖注入,还需要添加Bean后置处理器进行处理。由于第4步注册过BeanDefinition了(registerAnnotationConfigProcessors),我们现在只需要将它们添加到beanFactory的beanPostProcessors中就行了。

  • internalAutowiredAnnotationProcessor:@Autowired
  • internalCommonAnnotationProcessor:@Resource

因此,在geanBean()之前,执行添加如下代码:

beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);

重新运行:

在这里插入图片描述

bean02被成功注入了。

6. 让所有的单例bean初始化时加载

目前所有的单例bean都是懒加载的,只有在getBean()时才会创建。但是实际上应该在应用启动的时候就把大部分的bean加载,而不是使用到时才加载的。

只需开启beanFactory的初始化加载就行了。

// 初始化所有的单例Bean
beanFactory.preInstantiateSingletons();

System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Component01 bean01 = beanFactory.getBean(Component01.class);
System.out.println("从容器中获取的bean01:" + bean01);
System.out.println("被依赖注入的bean02:" + bean01.getBean02());

如何去验证呢?我们在getBean()之前,先输出了一行分隔符。可以看到构造方法在分割符之前就被调用了。

在这里插入图片描述

7. 总结

BeanFactory不会做:

  • 不会主动调用BeanFactory后置处理器(对应本文第4点)
  • 不会主动添加Bean后置处理器(对应本文第4、5点)
  • 不会主动初始化单例(对应本文第6点)
  • 不会解析beanFactory,不会解析${}和#{}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值