1.@Con?guration使用
官方文档描述:
用@Con?guration注释类表明其主要目的是作为bean定义的源
@Con?guration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/** * 说明:此处@Configuration 注解的作用, * 1、使配置类变成了full类型的配置类,spring在加载Appconfig的时候,Appcon?g由普通类型转变为cglib代理类型 , * 2、在 @Bean method中使用,是单例的,不会创建对个对象 */ @ComponentScan ( "com.jiagouedu" ) @Configuration public class AppConfig { @Bean public User user(){ System.out.println( "-----initMethod = \"user\"-return user -----" ); return new User(); } @Bean public Cat cat(){ return new Cat(); } @Bean //条件注解,只有TestConditional返回为true时,才能实例化Fox @Conditional (value = TestConditional. class ) public Fox fox(){ //假如 Appconfig上使用了 @Configuration注解,cat()方法不会每次都返回一个新的cat 对象,而是返回一个公共的代理对象 ; System.out.println( "test conditional" ); return new Fox(cat()); } |
2 配置@Configuration和不配置的区别?
使用@Configuration注解后,在调用方法 fox()创建 fox实例的时候,需要参数 cat,调用方法cat()生成cat实例,此时会去spring的单例bean工厂获取cat的单例bean的实例;
不使用@Configuration注解,实例化fox的时候,每次都会创建一个新的 cat对象,供实例化fox使用;
原因分析
@Con?guration修饰的AppCon?g是一个cglib的代理对象
1
|
//bat.ke.qq.com.config.AppConfig$$EnhancerBySpringCGLIB$$c983ca26@50a638b5 <br> System.out.println(context.getBean("appConfig")); |
可以看出appCon?g是一个代理对象,此时调用myService()方法,会去执行 BeanMethodInterceptor#intercept,终会从容器中获取bean
1
2
|
new fox(cat()) <br> >ConfigurationClassEnhancer.BeanMethodInterceptor#intercept <br> >ConfigurationClassEnhancer.BeanMethodInterceptor#resolveBeanReference Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :beanFactory.getBean(beanName)); //从容器中获取bean |
1
|
<br> |
所以@Con?guration 保证了配置类的内部方法之间依赖调用时都从容器中获取bean.
3.@Con?guration源码分析
AppCon?g变为AppCon?g$EnhancerBySpringCGLIB
AppCon?g 在容器启动前注册到容器
1
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig. class ); <br>> // 注册AppConfig, ApplicationContext传入的配置类 <br> register(annotatedClasses); <br> refresh();// 启动容器 |
此时,AppCon?g的beanDe?nition的属性beanClassName还是普通类型 bat.ke.qq.com.con?g.AppCon?g,
当容器启动过程中,调用invokeBeanFactoryPostProcessors(beanFactory)方法后,beanClassName 已经变为
了AppCon?g$$EnhancerBySpringCGLIB 类型.
1
|
AbstractApplicationContext#refresh >invokeBeanFactoryPostProcessors(beanFactory); // AppConfig--AppConfig$$EnhancerBySpringCGLIB |
类型改变原因跟踪 :
1
2
|
invokeBeanFactoryPostProcessors(beanFactory); <br>>PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableL istableBeanFactory, java.util.List<BeanFactoryPostProcessor>) <br>> //此方法会拿到ConfigurationClassPostProcessor <br> beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class) <br> <br> // 会调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 解析注 解,注册bean ;<br> invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);<br> //会调用 ConfigurationClassPostProcessor#postProcessBeanFactory <br> invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); |
调用 Con?gurationClassPostProcessor#postProcessBeanDe?nitionRegistry 会将 AppCon?g 的配置 类属性标注为full
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
ConfigurationClassPostProcessor#processConfigBeanDefinitions >ConfigurationClassUtils#checkConfigurationClassCandidate // 判断是否有配置@Configuration if (isFullConfigurationCandidate(metadata)) { // 设置 org.springframework.context.annotation.ConfigurationClassPostProcessor.configura tionClass为full beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } // 判断是否配置 @Component,@ComponentScan,@Import,@ImportResource 和方法配置了@Bean else if (isLiteConfigurationCandidate(metadata)) { // 设置 org.springframework.context.annotation.ConfigurationClassPostProcessor.configura tionClass为lite beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } |
调用Con?gurationClassPostProcessor#postProcessBeanFactory 会先判断AppCon?g是否是full,如果 是将AppCon?g的属性beanClassName替换为cglib类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
ConfigurationClassPostProcessor#postProcessBeanFactory > // 增强@Configuration修饰的配置类 AppConfig--->AppConfig$$EnhancerBySpringCGLIB enhanceConfigurationClasses(beanFactory); >ConfigurationClassPostProcessor#enhanceConfigurationClasses // 判断配置类是否是full if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) // 转换为cglib类型 Class<?> enhancedClass = enhancer.enhance(configClass, this .beanClassLoader); > ConfigurationClassEnhancer#enhance // 使用一个CGLIB增强器创建配置类configClass的子类enhancedClass Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader)); |
总结:
1.表明当前类是一个配置类,是方法bean的源
2.将@Con?guration配置的AppCon?g的beanDe?nitioin属性赋值为full类型的,保证AppCon?g类型 可以转变为cglib类型
3.将@Con?guration配置的AppCon?g由普通类型转变为cglib代理类型,后会生成cglib代理对象,通 过代理对象的方法拦截器,
可以解决AppCon?g内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现
原文:https://www.cnblogs.com/hippoppower/p/14953911.html