SpringBoot快速入门-@Configuration注解使用详解

想要真正了解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
*/

获取的对象到底是单例还是多例,一定要关注获取对象的来源对象到底是谁,这样才能保证代码的正确性。