@Configuration的神秘面纱

@Configuration的使用

@Configuration我们一般用来定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些被@Bean定义的方法将会被用来产生一个bean(这些方法就像一个beanFactoryMethod,用来生成bean的)。使用如下:

@Configuration
public class ConfigurationBean {

    @Bean
    public Dog dog() {
        System.out.println("dog;------");
        return new Dog();
    }

    @Bean
    public Rabbit rabbit() {
        System.out.println("rabbit;------");
        return new Rabbit();
    }
}

这样我们就定义了两个单例bean,dog和rabbit。这就类似使用xml中的(@Configuration)和(@Bean)。

@Configuration的探究

我们看看@Configuration中定义是怎么样的

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	@AliasFor(annotation = Component.class)
	String value() default "";

	boolean proxyBeanMethods() default true;
}

从定义中可以看出,@Configuration还是一个@Component,也就是说他拥有@Componet的功能,可以用来定义一个bean。那么它和Component到底有啥区别呢?我们不妨将ConfigurationBean上的@Configuration换成@Component,看看是否能定义出dog和rabbit这两个bean出来。
在这里插入图片描述
从结果中可以看到确实是可以定义出来这两个bean的。也就说明@Configuration的作用并不在于此。 其实通过@import ConfigurationBean进来也能达到同样的效果。其实@Configuration的作用用来标识对标志类的进行代理,使得@Bean方法能够被其他@Bean方法多次调用能返回同一个对象,达到单例的效果。

@Configuration
public class ConfigurationBean {

    @Bean
    public Dog Dog() {
        System.out.println("dog;------");
        Rabbit rabbit = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit);
        Rabbit rabbit1 = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit1);
        
        return new Dog();
    }

    @Bean
    public Rabbit rabbit() {
        System.out.println("rabbit;------");
        return new Rabbit();
    }
}

由程序上可以看出,dog() 方法中调用了两次rabbit()方法,按照正常逻辑,应该每调用一次,就应该返回一个新的对象。让我们来看看运行的结果
在这里插入图片描述

可以看到,每次调用都是同一个对象。如果将@Configuration换成@Component

@Component
public class ConfigurationBean {

    @Bean
    public Dog Dog() {
        System.out.println("dog;------");
        Rabbit rabbit = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit);
        Rabbit rabbit1 = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit1);

        return new Dog();
    }

    @Bean
    public Rabbit rabbit() {
        System.out.println("rabbit;------");
        return new Rabbit();
    }
}

我们再来看看结果如何
在这里插入图片描述
可以看到每次的都是新的对象。这就是它的作用,当然,处理将将@Configuration换成@Component外,也可以

@Configuration(proxyBeanMethods = false)
public class ConfigurationBean {

    @Bean
    public Dog Dog() {
        System.out.println("dog;------");
        Rabbit rabbit = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit);
        Rabbit rabbit1 = rabbit();
        System.out.println("调用 rabbit() ---" + rabbit1);

        return new Dog();
    }

    @Bean
    public Rabbit rabbit() {
        System.out.println("rabbit;------");
        return new Rabbit();
    }
}

这样也能返回不一样的对象。和上面是一样的效果。

why?

这是为什么呢?这是因为如果加了@Configuration,并且proxyBeanMethods = true(默认就是true)的话,spring就会对加了改注解的类进行代理(官方称它为增强),改变@Bean的方法的逻辑,改为:
在这里插入图片描述
红色部分就是代理的逻辑。从图中可以看出,如果我们在原始方法中去调用其他factoryMethod的话,它就method==currentInvokedFactoryMethod的条件就不会成立,那么他就直接是从beanFactory中获取,保证了每次请求都是返回同一个对象。


版权声明:本文为weixin_43415818原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。