想要真正了解SpringBoot,需要先搞明白Spring中的一些注解的作用,因为这些注解在SpringBoot中使用的频率非常高,@Configuration注解就是我们需要学习的注解之一。
@Configuration标注一个类是配置类,在这个配置类内部可以使用@Bean来创建对象,且对象默认是单例的。
SpringBoot启动时,会扫描并加载@Configuration标注的类,并将其定义的Bean加载到ioc容器中。
我们来看演示代码:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
/**
* Configuration的使用详解
*/
@Configuration
public class SpringBootConfiguration_3 {
@Bean
public Person person() {
return new Person();
}
}
基于这个配置类,创建了Person的Bean,这个Bean在全局是单例的,我们来验证一下。
启动类中的代码get了两个Person,来判断一下是否是一个
public static void main( String[] args ) {
ConfigurableApplicationContext run = SpringApplication.run(App.class, args);
System.out.println("SpringBoot Web-starter默认加载的组件数:" + run.getBeanDefinitionCount());
Arrays.stream(run.getBeanDefinitionNames()).forEach(System.out::println);
Person person1 = run.getBean("person", Person.class);
Person person2 = run.getBean("person", Person.class);
System.out.println("person1 == person2:" + (person1 == person2));
}
/* 输出
person1 == person2:true
*/
如果想要每次都获取的Bean都是一个新的对象,在传统的Spring项目中,只需要在xml中bean定义的位置添加一个属性scope=”prototype”,那么在SpringBoot中该如何使用呢?
我们先来看看我们自定义的Configatuation的对象类型,在主程序中添加两行代码:
public static void main( String[] args ) {
ConfigurableApplicationContext run = SpringApplication.run(App.class, args);
SpringBootConfiguration_3 sbc3 = run.getBean(SpringBootConfiguration_3.class);
System.out.println(sbc3);
Person p1 = sbc3.person();
Person p2 = sbc3.person();
System.out.println("p1 == p2:" + (p1 == p2));
}
/*输出如下:
com.itzhimei.handle.SpringBootConfiguration_3$$EnhancerBySpringCGLIB$$e350cb32@64b64200
p1 == p2:true
*/
我们再来看第二个例子,等两个例子看完,我们对比就能看出结果了。
我们在自定义的Configatuation的类上做一点修改,配置定义上添加如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
/**
* Configuration的使用详解
*/
@Configuration(proxyBeanMethods = false)
public class SpringBootConfiguration_3 {
@Bean
public Person person() {
return new Person();
}
}
再运行主程序查看结果:
/*输出如下:
com.itzhimei.handle.SpringBootConfiguration_3@742b1b0b
p1 == p2:false
*/
结论:
我们可以看到自定义的SpringBootConfiguration_3配置类实际对象是Spring生成的一个CGLIB的代理类,此时我们每次都是从这个代理类调用getXXX方法,获取的都是Spring容器中的同一个对象。
如果在配置类的@Configaturation后面加上(proxyBeanMethods = false),此时Spring创建的对象就不再是代理对象,而是一个普通的配置组件对象,此时再基于这个配置组件获取其中定义的Bean,每次获取的都是new出来的一个新对象。
如果始终都是使用SpringBoot上下文对象获取Bean,那么始终都是同一个对象,代码:
ConfigurableApplicationContext run = SpringApplication.run(App.class, args);
Person person1 = run.getBean("person", Person.class);
Person person2 = run.getBean("person", Person.class);
System.out.println("person1 == person2:" + (person1 == person2));
/* 输出
person1 == person2:true
*/
获取的对象到底是单例还是多例,一定要关注获取对象的来源对象到底是谁,这样才能保证代码的正确性。