spring中@Configuration注解的作用


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM