1.@Configuration使用
官方文檔描述:
用@Configuration注釋類表明其主要目的是作為bean定義的源
@Configuration類允許通過調用同一類中的其他@Bean方法來定義bean之間的依賴關系
代碼示例:
/**
* 說明:此處@Configuration 注解的作用,
* 1、使配置類變成了full類型的配置類,spring在加載Appconfig的時候,Appconfig由普通類型轉變為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使用;
原因分析
@Configuration修飾的AppConfig是一個cglib的代理對象
//bat.ke.qq.com.config.AppConfig$$EnhancerBySpringCGLIB$$c983ca26@50a638b5
System.out.println(context.getBean("appConfig"));
可以看出appConfig是一個代理對象,此時調用myService()方法,會去執行 BeanMethodInterceptor#intercept,終會從容器中獲取bean
new fox(cat())
>ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
>ConfigurationClassEnhancer.BeanMethodInterceptor#resolveBeanReference Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :beanFactory.getBean(beanName)); //從容器中獲取bean
所以@Configuration 保證了配置類的內部方法之間依賴調用時都從容器中獲取bean.
3.@Configuration源碼分析
AppConfig變為AppConfig$EnhancerBySpringCGLIB
AppConfig 在容器啟動前注冊到容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(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(ConfigurableL istableBeanFactory, 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.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);
}
調用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的子類enhancedClass Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
總結:
1.表明當前類是一個配置類,是方法bean的源
2.將@Configuration配置的AppConfig的beanDefinitioin屬性賦值為full類型的,保證AppConfig類型 可以轉變為cglib類型
3.將@Configuration配置的AppConfig由普通類型轉變為cglib代理類型,后會生成cglib代理對象,通 過代理對象的方法攔截器,
可以解決AppConfig內部方法bean之間發生依賴調用的時候從容器中去獲取,避免了多例的出現
