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之間發生依賴調用的時候從容器中去獲取,避免了多例的出現