使用BeanDefinitionRegistryPostProcessor扫描指定包下Bean对象时,@Configuration无法创建内部中@Bean的类

news/2024/11/30 15:29:01/

文章目录

  • 1. 前言
  • 2. 先说结论
  • 3. 代码验证

1. 前言

  1. 在之前工作中需要设计SDK(第三方jar包),该SDK中是有bean对象的,从而需要考虑该包下的会成为Bean的类要如何被spring扫描到从而创建,因此写了如下文章:
    1. 设计第三方jar包中有bean对象时,要如何自动加载到被引用的应用中(EnableAutoConfiguration、BeanDefinitionRegistryPostProcessor使用)
  2. 上文中介绍了三种方式:
    1. 使用@ComponentScan指定需要扫描路径
    2. 使用EnableAutoConfiguration自动装配 + @Configuration
    3. 使用EnableAutoConfiguration自动装配 + BeanDefinitionRegistryPostProcessor
  3. 第一种首先被我排除使用,不优雅,第二种,我不希望每次有个类要创建Bean对象,都要在@Configuration的类中加上@Bean的方法,因此选择了第三种。
  4. 但万万没想要,第三种有大坑,比如它无法创建@Configuration内部中@Bean的类。
  5. 案例如下:
    在这里插入图片描述
    在这里插入图片描述

2. 先说结论

  1. 在第三方jar中,若使用了BeanDefinitionRegistryPostProcessor扫描指定包下创建Bean的时候,会把带@Configuration注解的类创建为Bean对象,但其内部的@Bean、@ConditionalOnBean等类似注解都不会失效
  2. 因为BeanDefinitionRegistryPostProcessor扫描指定包,是真的只是看包内的类上是否有@Component注解,有则创建bean对象而已,不会做其他额外事情。
  3. 想要在第三方jar中@Configuration注解的类A中创建@Bean的对象,得使用自动装配该类A,才会生效
  4. 也可以使用@ComponentScan指定需要扫描路径,这个方式也生效。

3. 代码验证

  1. 通常在自己本项目中是如下使用的:
    在这里插入图片描述

    即只要被自己扫描扫描到的@Configuration可以生效,因此我们可以在启动类上加上,第三方jar包的路径:
    在这里插入图片描述

  2. 当然这种方式固然可以解决,但不是最优解,毕竟不希望使用SDK的每个项目都要加上@ComponentScan

  3. 下一种解决方式:在SDK中的自动装配加上@Configuration的类
    在这里插入图片描述
    在这里插入图片描述

  4. 似乎到这里就应该收尾了,上述也验证了在自动装配中加上@Configuration的类就可以创建内部的被@Bean注解的类了,但这里还有个小细节。

  5. 不知道大家发现没有,在上图中,有SDK中的BeanConfig类,以及本项目中的NeiBuConfig类,仔细观察debug后面的对象类型

  6. 我们发现了,在SDK中的BeanConfig类确实是它自己的Bean对象,而在本项目中的NeiBuConfig类,却是代理对象。如下图:
    在这里插入图片描述

  7. 来来来,我们现在把SDK中使用BeanDefinitionRegistryPostProcessor的类,取消在spring.factories中的配置,如下图:
    在这里插入图片描述

  8. 在本项目中,重新加载并查看结果:
    在这里插入图片描述

  9. 发现现在无论是哪里的Config配置,都是代理对象了,首先先明确一个知识点,spring会把被@Configuration注解的类搞成代理对象,创建内部被@Bean的类

  10. 到这里突然悟了, BeanDefinitionRegistryPostProcessor扫描指定包,是真的看包内的类上是否有@Component注解,有则创建bean对象而已

  11. 到这里可能有人有点懵,这里小总结一下

    1. 使用BeanDefinitionRegistryPostProcessor扫描指定包下创建Bean对象的方式中,其功能是看包下的类上是否有@Component注解,有则创建对象,就仅仅而已
    2. 若遇到包下有@Configuration注解的类,因为@Configuration注解里面有@Component注解,所以包下有@Configuration注解的类会被创建为Bean对象。
    3. 而其实在自身项目中有@Configuration注解的类spring实际上是会生成代理对象,从而创建里面被@Bean的bean对象
    4. 根据上述点,所以BeanDefinitionRegistryPostProcessor的方式中有@Configuration注解的类,只是生成bean对象不是代理对象从而不会创建内部的bean对象
    5. 如果使用BeanDefinitionRegistryPostProcessor的方式扫描包中有@Configuration注解的类,再加上自动装配上带上@Configuration注解的类,则实际上容器中会有类A的两个bean对象
  12. 来,再证明一下,如果BeanDefinitionRegistryPostProcessor扫描指定包下有@Configuration注解的类A,以及使用自动装配加上类A,那么理论上来说会有两个bean对象,有个是类A的普通对象,有个是类A的代理对象,如下图:
    在这里插入图片描述
    在这里插入图片描述


http://www.ppmy.cn/news/39090.html

相关文章

计算虚拟化之内存管理

CPU 的虚拟化是用户态的 qemu 和内核态的 KVM 共同配合完成的。它们二者通过 ioctl 进行通信。对于内存管理来讲,也是需要这两者配合完成的。 操作系统给每个进程分配的内存都是虚拟内存,需要通过页表映射,变成物理内存进行访问。当有了虚拟…

netty 实现websocket 携带参数建立连接

Netty提供了很好的WebSocket支持,可以通过添加WebSocketServerProtocolHandler实现暴露一个WebSocket接口。但是,如果需要在WebSocket的URI中添加参数queryString,例如/im/ws?w221100234&t99,则连接可能无法建立,…

MySQL学习笔记(十五)——索引的创建和设计原则

1. 为什么使用索引 1.1 不加索引 没有索引,整张表读取数据,然后利用数据来比较条件,捞出符合条件的数据,表有很多数据,这些数据都会通过磁盘IO来读取,很耗时。 1.2 加索引 加索引后 ,通过索引…

Mybatis高阶使用

1.Mybatis拦截器 Mybatis——拦截器Interceptor_mybatis interceptor_七海健人的博客-CSDN博客 mybatis拦截器使用及原理_metaobject.forobject_huang_ma的博客-CSDN博客 手把手教你开发 MyBatis 插件 - 知乎 2.Mybatis工具类 MetaObject MetaClass https://www.cnblogs.co…

leetcode 面试题 17.06. 2出现的次数

编写一个方法,计算从 0 到 n (含 n) 中数字 2 出现的次数。 示例: 输入: 25 输出: 9 解释: (2, 12, 20, 21, 22, 23, 24, 25)(注意 22 应该算作两次) 该问题用的方法数数组dp,首先我通过总结规律写出了相关的code。使用一个dp数组记录10i10^i10i以内会出…

加多宝二次创业五周年:解锁品牌持续增长密码

今年作为后疫情时代元年,首要的任务是提振经济、重振信心,其中消费市场的提振至关重要。 春江水暖鸭先知。每当消费市场开始复苏,食品饮料行业的回暖一般会更明显。而要扩大食品饮料的消费规模、提振消费信心,关键在于品牌结合外…

NVIDIA jetson tensorrt加速yolov5摄像头检测

link 在使用摄像头直接检测目标时,检测的实时画面还是有点慢,下面是tensorrt加速过程记录。 一、设备 1、设备jetson agx xavier 2、jetpack4.6.1 3、tensorrt 8.2.1.8 4、conda虚拟环境 python3.6 二、虚拟环境搭建及依赖 1、参考此博客安装torch Nvidi…

13回归网络:HTTP/2是怎样的网络协议?

本篇文章我们先放下实践,回归网络,深入gRPC底层的HTTP/2协议,去探究一下框架底层网络协议的原理,提升对高性能网络协议的认知,相信读完这篇文章以后,我们就可以了解HTTP/2有哪些优势,为什么gRPC要使用HTTP/2作为底层的传输协议。 在众多研究HTTP/2的博客和资料中,最具…