@Configuration注解的作用

1.@Configuration使用 

  官方文档描述:

  用@Configuration注释类表明其主要目的是作为bean定义的源

  @Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系

代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/**

 * 说明:此处@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的代理对象

1

//bat.ke.qq.com.config.AppConfig$$EnhancerBySpringCGLIB$$c983ca26@50a638b5 <br>  System.out.println(context.getBean("appConfig"));

  可以看出appConfig是一个代理对象,此时调用myService()方法,会去执行 BeanMethodInterceptor#intercept,终会从容器中获取bean

1

2

new fox(cat()) <br>  >ConfigurationClassEnhancer.BeanMethodInterceptor#intercept <br>  >ConfigurationClassEnhancer.BeanMethodInterceptor#resolveBeanReference

  Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :beanFactory.getBean(beanName)); //从容器中获取bean<br> 

  所以@Configuration 保证了配置类的内部方法之间依赖调用时都从容器中获取bean.

3.@Configuration源码分析 

  AppConfig变为AppConfig$EnhancerBySpringCGLIB
  AppConfig 在容器启动前注册到容器

1

AnnotationConfigApplicationContext context =      new AnnotationConfigApplicationContext(AppConfig.class); <br>> //  注册AppConfig, ApplicationContext传入的配置类 <br>  register(annotatedClasses); <br>  refresh();// 启动容器

    

此时,AppConfig的beanDefinition的属性beanClassName还是普通类型 bat.ke.qq.com.config.AppConfig,

  当容器启动过程中,调用invokeBeanFactoryPostProcessors(beanFactory)方法后,beanClassName 已经变为
了AppConfig$$EnhancerBySpringCGLIB 类型.

1

AbstractApplicationContext#refresh >invokeBeanFactoryPostProcessors(beanFactory); // AppConfig--AppConfig$$EnhancerBySpringCGLIB

  类型改变原因跟踪 :

1

2

invokeBeanFactoryPostProcessors(beanFactory); <br>>PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableL istableBeanFactory, java.util.List<BeanFactoryPostProcessor>) <br>>     //此方法会拿到ConfigurationClassPostProcessor <br>    beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class) <br>        <br>  // 会调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 解析注 解,注册bean ;<br>  invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);<br>

  //会调用 ConfigurationClassPostProcessor#postProcessBeanFactory   <br>  invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

  

调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 会将 AppConfig 的配置 类属性标注为full

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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类型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值