• 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之间发生依赖调用的时候从容器中去获取,避免了多例的出现

  • 相关阅读:
    Maven学习
    Oracle_SQL函数-单行函数
    Java 8新特性-5 内建函数式接口
    量子优势
    配置Emeditor编译运行JAVA,附私家珍藏版
    配置Emeditor编译运行JAVA,附私家珍藏版
    Notepad2-mod,轻量级文本编辑器、代替记事本的最佳选择
    三星S7短信不能提示的处理方法
    三星S7短信不能提示的处理方法
    说说宾得机身的十大人性化设定和功能[转]
  • 原文地址:https://www.cnblogs.com/wl20200316/p/12579982.html
Copyright © 2020-2023  润新知