@Configuration
在聊@Configuration之前,先说一下spring中声明bean的方法。一开始是使用xml配置文件的,如下代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
使用bean标签,id是该bean的id,是唯一的标识,class是要声明为bean对象的类,property是bean对象里面的属性。通过这种方式的确可以声明一个bean,但是却十分的麻烦,在创建容器的时候,还要读取该xml文件。于是可以用另外一种简单的方式来替代配置文件声明bean的方式,使用@Configuration注解,使用该注解等同于使用xml配置文件,下面是注解使用的方式:
@Configuration
public class Myconfig {
@Bean
public User user1() {
return new User();
}
@Configuration作用在类上面,表示该类是一个配置类,等同于之前的xml配置文件;@Bean注解作用在方法上面,方法的名字user1就是要声明bean的名字,方法的返回类型User就是Bean的类型。可以看到,通过注解配置的方式是完全等同于使用xml文件的方式的,只不过之前spring读取的是xml文件,现在读取的是该配置类。
然后运行程序,在启动类中测试,可以发现User 类型的bean 已经存在于ioc容器当中了:
@SpringBootApplication
public class SpringbootApplicationTest {
public static void main(String[] args) {
//run 就是ioc容器
ConfigurableApplicationContext run = SpringApplication.run(SpringbootApplicationTest.class, args);
Object user1 = run.getBean("user1");
System.out.println(user1);
}
}
打印的结果:
proxyBeanMethods属性
需要注意的是@Configuration里面有一个属性,一般不写表示默认为true,该属性的意思为是否要代理用户去拿spring容器里面的对象,该属性为proxyBeanMethods,贴图如下:
这里我们就知道了其实用@Configuration标识的类默认是一个代理类:
如果将属性proxyBeanMethods设置为false,则不会是代理类,也就不会从spring容器里面取东西,设置如下:
打印Myconfig类:
该属性的意义就是让bean保持单例。每次要创建一个bean都会从容器中去寻找,如果有该bean了,则直接获取,没有的话再进行创建。
使用场景:对象之间的依赖引用。
下图是配置类,里面声明了两个bean,并且Pet对象作为了User类里面的一个属性。
@Configuration(proxyBeanMethods = false)
public class Myconfig {
@Bean
public User user1() {
User zhangsan = new User();
zhangsan.setPet(pet1());
return zhangsan;
}
@Bean
public Pet pet1() {
return new Pet();
}
}
这表示已经在容器中创建了两个对象bean,现在我不想用容器里面的bean,只需要把属性proxyBeanMethods设置为false即可,测试的代码如下:
@SpringBootApplication
public class SpringbootApplicationTest {
public static void main(String[] args) {
//run 就是ioc容器
ConfigurableApplicationContext run = SpringApplication.run(SpringbootApplicationTest.class, args);
//容器中的user1
User user = run.getBean("user1", User.class);
//容器中的pet1
Pet pet = run.getBean("pet1", Pet.class);
//如果设置@Configuration(proxyBeanMethods = false),则生成的对象和容器中对象不是一个。
System.out.println(user.getPet() == pet);
}
}
打印的结果为false:
@Import
该注解的意思顾名思义,就是直接向spring容器中导入bean。导入的是类型是class:
现在想要直接向spring容器中导入User类型的一个对象,方法如下:
@Configuration(proxyBeanMethods = false)
@Import({User.class})
public class Myconfig {
@Bean
public User user1() {
User zhangsan = new User("zhangsan", 18);
return zhangsan;
}
}
测试的代码:
@SpringBootApplication
public class SpringbootApplicationTest {
public static void main(String[] args) {
//run 就是ioc容器
ConfigurableApplicationContext run = SpringApplication.run(SpringbootApplicationTest.class, args);
//获取所有类型为User的bean
String[] beanNamesForType = run.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
}
}
打印结果如下:
一个是全限定为名的bean,也就是使用@Import注解导入的,另一个是声明的bean。
@Conditional
该注解的意思是要进行条件判断,只要满足该条件的话才执行某些方法,下面是@Conditional所有的注解:
举一个例子,下面的意思如果容器中不存在Pet类型的bean,再创建user1 的bean对象:
@Configuration
public class Myconfig {
@Bean
public Pet pet1() {
return new Pet("tomcat");
}
@Bean
@ConditionalOnMissingBean(Pet.class)
public User user1() {
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(pet1());
return zhangsan;
}
}
测试代码:
@SpringBootApplication
public class SpringbootApplicationTest {
public static void main(String[] args) {
//run 就是ioc容器
ConfigurableApplicationContext run = SpringApplication.run(SpringbootApplicationTest.class, args);
//判断容器中是否存在user1
boolean user1 = run.containsBean("user1");
System.out.println(user1);
}
}
因为容器中存在Pet类型的对象,所以spring不会创建user1,最终打印的结果为false。
该注解不仅可以作用在方法上,作用在类上也是可以的,表示如果满足某个条件在执行类里面的所有方法。使用的场景一般是多个对象之间的组合,当满足或者不足某个对象的时候再创建另外一个对象。
@ConfigurationProperties
该注解的作用是读取配置文件中的值,并与类中的属性进行绑定、赋值。
现在声明一个yml文件:
然后声明一个实体类:
@Component
//下面代码的含义是读取配置文件前缀为“mycar”的内容并将内容赋值给Car对象,但前提是必须将对象放到ioc容器中才能生效。
@ConfigurationProperties(prefix = "mycar")
@Data
public class Car {
private String brand;
private Integer price;
}
配置文件中的brand和price是Car类中的两个属性;当使用@ConfigurationProperties的时候,会把配置文件中的值给该类的属性赋上。但是该类一定要加上@Component注解,因为如果想要让该操作生效,一定要把该类作为spring管理的对象才可以。
测试代码:
@RestController
public class ControllerTest {
@Autowired
Car car;
@RequestMapping("/test")
private Car test() {
return car;
}
}
测试结果: