SpringBoot的自动化配置对于开发者来说,可能会从不同的角度体现这一点。首先搭建一个SpringBoot工程,接下来第一件事情可能就是添加依赖,在添加依赖的时候,我们是不需要添加版本号,给我们带来了很大的方便,做开发的小伙伴可能遇到不同版本的SpringBoot,对其他框架的依赖版本是有要求的,否则会出现意想不到的错误。那么SpringBoot是如何帮助我们自动添加版本的呢?我们知道,在工程的pom.xml文件中一般都会加这个父类依赖。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
这个依赖中我们要指明SpringBoot的版本号,接下来看一下spring-boot-starter-parent的依赖关系,打开对应工程的仓库地址:
C:\Users\86152.m2\repository\org\springframework\boot\spring-boot-starter-parent\2.0.4.RELEASE,打开文件spring-boot-starter-parent-2.0.4.RELEASE.pom
从依赖的关系看,spring-boot-starter-parent主要功能归纳为:
- 添加对spring-boot-dependencies的依赖
- 指定工程的编码格式
- 指定工程依赖的JDK版本
- 自动化打包与插件配置
- 资源过滤配置
我们根据指定的路径(…/…/spring-boot-dependencies)查看dependencies的依赖关系:
从上图看到,dependencies的依赖文件列举的属性properties里展示了各种依赖包的版本,正是由于这个版本的存在,我们在开发时才不必添加版本,就可以下载到相应的依赖。
SpringBoot自动配置的核心是源于添加注解,就是指在不同的添加下生成不同的bean,或者是在某个bean创建完成后,才去生成其他的bean,诸如此类i,在特定的条件下创建bean的行为。比较常见的添加注解有:
@Conditional 依赖的条件
@ConditionalOnBean 在某个Bean存在的条件下
@ConditionalOnMissingBean 在某个Bean不存在的条件下
@ConditionalOnClass 在某个Class存在的条件下
@ConditionalOnMissingClass 在某个Class不存在的条件下
实战
以@Conditional为例,说明条件注解的作用。条件注解在Spring中已经引入,在SpringBoot中应用广泛。
新建一个标准的maven工程,在pom.xml添加如下依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
1、定义一个汽车的接口类及声明方法:
public interface Car {
public String getBrand(); //用于获取所属品牌
}
2、创建两个实现类:
public class BuickCar implements Car {
public String getBrand() {
return "别克汽车";
}
}
public class ToyotaCar implements Car{
public String getBrand() {
return "丰田汽车";
}
}
3、创建两个条件类,作为生成不同bean的条件
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class BuickCondition implements Condition {
public boolean matches(ConditionContext con, AnnotatedTypeMetadata meta) {
return con.getEnvironment().getProperty("car").equals("别克汽车");
}
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ToyotaCondition implements Condition {
public boolean matches(ConditionContext con, AnnotatedTypeMetadata meta) {
return con.getEnvironment().getProperty("car").equals("丰田汽车");
}
}
4、创建配置类:定义两个bean的名字均为car
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CarConfig {
@Bean("car")
@Conditional(BuickCondition.class)
Car buickCar() {
return new BuickCar();
}
@Bean("car")
@Conditional(ToyotaCondition.class)
Car toyotaCar() {
return new ToyotaCar();
}
}
5、测试:
public static void main(String[] args) {
AnnotationConfigApplicationContext actx = new AnnotationConfigApplicationContext();
actx.getEnvironment().getSystemProperties().put("car", "别克汽车");
actx.register(CarConfig.class);
actx.refresh();
Car car = (Car)actx.getBean("car");
System.out.println(car.getBrand());
}
结果:
如果在均不满足属性值的条件下,结果如下:
public static void main(String[] args) {
AnnotationConfigApplicationContext actx = new AnnotationConfigApplicationContext();
actx.getEnvironment().getSystemProperties().put("car", "汽车");
actx.register(CarConfig.class);
actx.refresh();
Car car = (Car)actx.getBean("car");
System.out.println(car.getBrand());
}
总结
通过上面的例子看出,条件注解控制了创建bean的行为,尽管我们在定义bean的时候,把两个bean定义为相同的名字(car),但是其创建的过程还是依赖条件属性。当不满足条件,Spring容器不会创建bean。在实际开发中,灵活运用条件注解,才能最大限度发挥Spring容器的功能。