本节学习SpringBoot原理解析和SpringBoot的一些高级特性。
1. Profile功能由于开发环境、测试环境和生产环境的配置都不一样,切换环境如果重新配置太麻烦。
SpringBoot引入了Profile功能可以帮助我们方便切换环境配置,具体信息参照 Spring官方文档 。
为了方便多环境适配,SpringBoot简化了Profile功能。
3.1 切换环境配置功能可以参照 测试环境配置文件命名规则
的方式来命名:application-
使用方式是在默认环境配置文件中指定spring.profiles.active属性,值为自定义的环境名称。
编写一个控制器来演示Profile功能:
@RestController
public class UserController {
@Value("${user.username:默认环境}") // 使用SpEL表达式取配置文件中的值进行注入,默认值为“默认环境”
private String name;
@GetMapping("/name")
public String getUserName() {
return "Hello, " + name;
}
}
上述代码中的name属性将取SpringBoot配置文件中的user.username属性的值。
编写测试环境的配置文件(application-test.yaml):
user: username: 测试环境 server: port: 8081
编写生产环境的配置文件(application-prod.yaml):
user: username: 生产环境 server: port: 8082
编写默认环境的配置文件(application.yaml):
# spring.profiles.active属性用于指定当前激活的环境配置
spring:
profile:
active:
不指定spring.profiles.active属性时SpringBoot会使用默认环境配置,发送/name请求测试,测试结果:
指定spring.profiles.active属性为test即测试环境时会使用测试环境配置,发送/name请求测试,测试结果:
指定spring.profiles.active属性为prod即生产环境时会使用生产环境配置,发送/name请求测试,测试结果:
3.1.2 使用带参运行命令切换环境配置上面的方法是在默认配置文件中写死的,还有另一种方式不必修改默认配置文件中的spring.profiles.active属性也能切换环境配置。
运行应用时可以带参运行,指定参数spring.profiles.active,值为环境名称。
拿上面的例子做测试,导入SpringBoot的Maven插件:
org.springframework.boot spring-boot-maven-plugin
运行Maven命令mvn clean和mvn package,将应用打包后,使用java -jar命令运行jar包,带入参数spring.profiles.active=test:
java -jar springboot_features-1.0-SNAPSHOT.jar --spring.profiles.active=test
运行界面:
可以看到SpringBoot已经识别了运行参数,已经切换到了测试环境的配置。发送/name请求测试,测试结果:
需注意,命令行参数会覆盖配置文件中定义的参数。
3.2 @Profile条件装配功能实际开发中我们有可能需要指定某个组件在某个环境中才能被注册到容器中的功能,使用Spring提供的@Profile注解即可实现,详细信息参照 Spring官方文档 。
注解@Profile的作用是可以根据当前环境,动态的激活和切换一系列组件。通常标注在组件类或组件方法上,用于条件装配。参数为value:
- String[] value:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件。
举个例子简单介绍@Profile注解的使用方式,编写一个控制器:
@RestController
public class EnvInfoController {
public String env; // 测试环境切换的组件
@Autowired
public void setEnv(String env) {
this.env = env;
}
@GetMapping("/env")
public String getCurrentEnv() {
return "Current Env:" + env;
}
}
编写一个配置类,用来注入测试环境切换的组件:
@Configuration
public class SpringConfig {
@Bean
@Profile("default") // 默认环境会装配此组件
public String envDefault() {
return "default";
}
@Bean
@Profile("test") // 测试环境会装配此组件
public String envTest() {
return "test";
}
@Bean
@Profile("prod") // 生产环境会装配此组件
public String envProd() {
return "prod";
}
}
测试结果:
| spring.profiles.active | 结果 |
|---|---|
| 不指定或default | |
| test | |
| prod |
有时候在某个环境下的配置文件需要定义大量配置,显得冗余杂乱,为此我们需要将不同模块的配置文件分开编写,比如数据库配置文件,消息队列配置文件等。
那么就需要将某个环境的全部配置文件全部导入,所以Spring提供了配置组的功能 (Spring官方文档) 。
使用上面的例子简单演示一下功能:
编写生产环境配置文件1(application-prod1.yaml):
user: username: 生产环境
编写生产环境配置文件1(application-prod2.yaml):
server: port: 8082
编写默认配置文件(application.yaml):
spring:
profiles:
active: prod
# spring.profiles.group.<配置组名>[个数]=<配置组内的配置文件名>
group:
prod[0]: prod1
prod[1]: prod2
# 上面的配置也可以写成这样:
# group:
# prod:
# - prod1
# - prod2
# 还也可以写成这样:
# group:
# prod: [prod1, prod2]
运行测试:
可以看到Spring成功识别了我们定义的配置组并加载了配置信息。
2. 外部化配置在实际开发中,数据库配置信息(账户密码等)直接写死在代码里面,后期需要更改时将会非常麻烦。于是Spring引入了外部化配置(Externalized Configuration)机制。
Spring提供了以下配置源(按加载优先级顺序,后者会覆盖前者):
- 由SpringApplication.setDefaultProperties方法定义的默认参数;
- 由@Configuration配置类的@PropertySource注解加载的参数;
- (常用)配置文件(如application.yaml);
- 由@RandomValuePropertySource加载的random.*类型参数;
- (常用)系统环境变量;
- Java系统参数(由System.getProperties方法获取的);
- 从java:comp/env获取的JNDI参数;
- ServletContext初始化参数;
- ServletConfig初始化参数;
- 由环境变量或系统参数中的SPRING_APPLICATION_JSON定义的参数(inline JSON);
- (常用)命令行参数;
- 测试方法中的属性(@SpringBootTest和其他测试注解加载的);
- 由@TestPropertySource注解加载的参数;
- 当DevTools可用时加载的DevTools全局配置(在$HOME/.config/spring-boot目录下)。
配置文件将会由如下顺序加载(按加载优先级顺序,后者会覆盖前者):
- jar包内的application.properties(.yaml)配置文件;
- jar包内的application-
.properties(.yaml)Profile环境配置文件; - jar包外的application.properties(.yaml)配置文件;
- jar包外的application-
.properties(.yaml)Profile环境配置文件。
Spring将会由如下顺序查找配置文件(按加载优先级顺序,后者会覆盖前者):
- classpath:根目录;
- classpath:config/目录;
- 应用所在的根目录;
- 应用所在的目录的/config目录;
- 应用所在的目录的/config目录的直接子目录(一层子目录)。
按照2.1章节的加载优先级,我们进行测试来验证优先级。
编写一个控制器:
@RestController
public class TestController {
@Value("${properties.location}")
private String propertiesLocation;
@GetMapping("/location")
public String getPropertiesLocation() {
return propertiesLocation;
}
}
五个配置文件:
# classpath:application.yaml properties: location: classpath:根目录
# classpath:config/application.yaml properties: location: classpath:/config目录
# jar包根目录/application.yaml properties: location: jar包所在根目录
# jar包根目录/config/application.yaml properties: location: jar包所在的目录的/config目录
# jar包根目录/config/test/application.yaml properties: location: jar包所在的目录的/config目录的直接子目录
测试结果:
| 配置文件位置(依次加入) | 图示 | 请求测试结果 |
|---|---|---|
| classpath:根目录 | ||
| classpath:/config目录 | ||
| jar包所在根目录 | ||
| jar包所在的目录的/config目录 | ||
| jar包所在的目录的/config目录的直接子目录 |



