文章目录
- 1. 前言
- 2. 先说结论
- 3. 代码验证
1. 前言
- 在之前工作中需要设计SDK(第三方jar包),该SDK中是有bean对象的,从而需要考虑该包下的会成为Bean的类要如何被spring扫描到从而创建,因此写了如下文章:
- 设计第三方jar包中有bean对象时,要如何自动加载到被引用的应用中(EnableAutoConfiguration、BeanDefinitionRegistryPostProcessor使用)
- 上文中介绍了三种方式:
- 使用@ComponentScan指定需要扫描路径
- 使用EnableAutoConfiguration自动装配 + @Configuration
- 使用EnableAutoConfiguration自动装配 + BeanDefinitionRegistryPostProcessor
- 第一种首先被我排除使用,不优雅,第二种,我不希望每次有个类要创建Bean对象,都要在@Configuration的类中加上@Bean的方法,因此选择了第三种。
- 但万万没想要,第三种有大坑,比如它无法创建@Configuration内部中@Bean的类。
- 案例如下:
2. 先说结论
- 在第三方jar中,若使用了BeanDefinitionRegistryPostProcessor扫描指定包下创建Bean的时候,会把带@Configuration注解的类创建为Bean对象,但其内部的@Bean、@ConditionalOnBean等类似注解都不会失效。
- 因为BeanDefinitionRegistryPostProcessor扫描指定包,是真的只是看包内的类上是否有@Component注解,有则创建bean对象而已,不会做其他额外事情。
- 想要在第三方jar中,@Configuration注解的类A中创建@Bean的对象,得使用自动装配该类A,才会生效。
- 也可以使用@ComponentScan指定需要扫描路径,这个方式也生效。
3. 代码验证
-
通常在自己本项目中是如下使用的:
即只要被自己扫描扫描到的@Configuration可以生效,因此我们可以在启动类上加上,第三方jar包的路径:
-
当然这种方式固然可以解决,但不是最优解,毕竟不希望使用SDK的每个项目都要加上@ComponentScan。
-
下一种解决方式:在SDK中的自动装配加上@Configuration的类
-
似乎到这里就应该收尾了,上述也验证了在自动装配中加上@Configuration的类就可以创建内部的被@Bean注解的类了,但这里还有个小细节。
-
不知道大家发现没有,在上图中,有SDK中的BeanConfig类,以及本项目中的NeiBuConfig类,仔细观察debug后面的对象类型
-
我们发现了,在SDK中的BeanConfig类确实是它自己的Bean对象,而在本项目中的NeiBuConfig类,却是代理对象。如下图:
-
来来来,我们现在把SDK中使用BeanDefinitionRegistryPostProcessor的类,取消在spring.factories中的配置,如下图:
-
在本项目中,重新加载并查看结果:
-
发现现在无论是哪里的Config配置,都是代理对象了,首先先明确一个知识点,spring会把被@Configuration注解的类搞成代理对象,创建内部被@Bean的类。
-
到这里突然悟了, BeanDefinitionRegistryPostProcessor扫描指定包,是真的看包内的类上是否有@Component注解,有则创建bean对象而已。
-
到这里可能有人有点懵,这里小总结一下:
- 使用BeanDefinitionRegistryPostProcessor扫描指定包下创建Bean对象的方式中,其功能是看包下的类上是否有@Component注解,有则创建对象,就仅仅而已。
- 若遇到包下有@Configuration注解的类,因为@Configuration注解里面有@Component注解,所以包下有@Configuration注解的类会被创建为Bean对象。
- 而其实在自身项目中有@Configuration注解的类,spring实际上是会生成代理对象,从而创建里面被@Bean的bean对象。
- 根据上述点,所以BeanDefinitionRegistryPostProcessor的方式中有@Configuration注解的类,只是生成bean对象,不是代理对象,从而不会创建内部的bean对象
- 如果使用BeanDefinitionRegistryPostProcessor的方式扫描包中有@Configuration注解的类,再加上自动装配上带上@Configuration注解的类,则实际上容器中会有类A的两个bean对象。
-
来,再证明一下,如果BeanDefinitionRegistryPostProcessor扫描指定包下有@Configuration注解的类A,以及使用自动装配加上类A,那么理论上来说会有两个bean对象,有个是类A的普通对象,有个是类A的代理对象,如下图: