@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中获取,保证了每次请求都是返回同一个对象。