spring中@Configuration注解的作用
本文内容纲要:
1.@Configuration使用
官方文档描述:
用@Configuration注释类表明其主要目的是作为bean定义的源
@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系
代码示例:
/**
*说明:此处@Configuration注解的作用,
*1、使配置类变成了full类型的配置类,spring在加载Appconfig的时候,Appconfig由普通类型转变为cglib代理类型,
*2、在@Beanmethod中使用,是单例的,不会创建对个对象
*/
@ComponentScan("com.jiagouedu")
@Configuration
publicclassAppConfig{
@Bean
publicUseruser(){
System.out.println("-----initMethod=\"user\"-returnuser-----");
returnnewUser();
}
@Bean
publicCatcat(){
returnnewCat();
}
@Bean
//条件注解,只有TestConditional返回为true时,才能实例化Fox
@Conditional(value=TestConditional.class)
publicFoxfox(){
//假如Appconfig上使用了@Configuration注解,cat()方法不会每次都返回一个新的cat对象,而是返回一个公共的代理对象
;
System.out.println("testconditional");
returnnewFox(cat());
}
2配置@Configuration和不配置的区别?
使用@Configuration注解后,在调用方法fox()创建fox实例的时候,需要参数cat,调用方法cat()生成cat实例,此时会去spring的单例bean工厂获取cat的单例bean的实例;
不使用@Configuration注解,实例化fox的时候,每次都会创建一个新的cat对象,供实例化fox使用;
原因分析
@Configuration修饰的AppConfig是一个cglib的代理对象
//bat.ke.qq.com.config.AppConfig$$EnhancerBySpringCGLIB$$c983ca26@50a638b5
System.out.println(context.getBean("appConfig"));
可以看出appConfig是一个代理对象,此时调用myService()方法,会去执行BeanMethodInterceptor#intercept,终会从容器中获取bean
newfox(cat())
>ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
>ConfigurationClassEnhancer.BeanMethodInterceptor#resolveBeanReference
ObjectbeanInstance=(useArgs?beanFactory.getBean(beanName,beanMethodArgs):beanFactory.getBean(beanName));//从容器中获取bean
所以@Configuration保证了配置类的内部方法之间依赖调用时都从容器中获取bean.
3.@Configuration源码分析
AppConfig变为AppConfig$EnhancerBySpringCGLIB
AppConfig在容器启动前注册到容器
AnnotationConfigApplicationContextcontext= newAnnotationConfigApplicationContext(AppConfig.class);
>//注册AppConfig,ApplicationContext传入的配置类
register(annotatedClasses);
refresh();//启动容器
此时,AppConfig的beanDefinition的属性beanClassName还是普通类型bat.ke.qq.com.config.AppConfig,
当容器启动过程中,调用invokeBeanFactoryPostProcessors(beanFactory)方法后,beanClassName已经变为
了AppConfig$$EnhancerBySpringCGLIB类型.
AbstractApplicationContext#refresh>invokeBeanFactoryPostProcessors(beanFactory);//AppConfig--AppConfig$$EnhancerBySpringCGLIB
**类型改变原因跟踪:**
invokeBeanFactoryPostProcessors(beanFactory);
>PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory,java.util.List<BeanFactoryPostProcessor>)
> //此方法会拿到ConfigurationClassPostProcessor
beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class)
//会调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry解析注解,注册bean;
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,registry);
//会调用ConfigurationClassPostProcessor#postProcessBeanFactory
invokeBeanFactoryPostProcessors(registryProcessors,beanFactory);
调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry会将AppConfig的配置类属性标注为full
ConfigurationClassPostProcessor#processConfigBeanDefinitions
>ConfigurationClassUtils#checkConfigurationClassCandidate
//判断是否有配置@Configuration
if(isFullConfigurationCandidate(metadata)){
//设置org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass为full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_FULL);
}
//判断是否配置@Component,@ComponentScan,@Import,@ImportResource和方法配置了@Bean
elseif(isLiteConfigurationCandidate(metadata)){
//设置org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass为lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_LITE);
}
调用ConfigurationClassPostProcessor#postProcessBeanFactory会先判断AppConfig是否是full,如果是将AppConfig的属性beanClassName替换为cglib类型
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的子类enhancedClassClass<?>enhancedClass=createClass(newEnhancer(configClass,classLoader));
总结:
1.表明当前类是一个配置类,是方法bean的源
2.将@Configuration配置的AppConfig的beanDefinitioin属性赋值为full类型的,保证AppConfig类型可以转变为cglib类型
3.将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,后会生成cglib代理对象,通过代理对象的方法拦截器,
可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现
本文内容总结:
原文链接:https://www.cnblogs.com/wl20200316/p/12579982.html