基础特性
SpringApplication
@SpringBootApplication
public class SpringbootSsmApplication {
public static void main(String[] args) {
// SpringApplication:Boot应用的核心API入口
SpringApplication.run(SpringbootSsmApplication.class, args);
//使用FluentBuilder API启动springboot
// ConfigurableApplicationContext context = new SpringApplicationBuilder()
// .sources(Parent.class)
// .child(Application.class)
// .bannerMode(Banner.Mode.OFF)
// .run(args);
}
}
Profiles
@Profile注解
用于标识该组件的生效环境,若未指定特定环境则为default环境
这里假设有3个不同的环境,分别为dev(开发环境),test(测试环境),prod(生产环境)
那么被@Profile({“dev”,“test”})标注的组件就只会在开发和测试环境生效
此时若我们在application.properties配置文件中集合指定环境(spring.profiles.active=dev,test),那么被dev或test标识的组件就会生效
注意,若没有被@Profile注解标识,那么表示在所有环境中都生效
# 环境指定
# 激活指定的一个或多个环境
spring.profiles.active = mygroup
# 为环境分组
spring.profiles.group.mygroup=dev,test
# 指定默认环境
spring.profiles.default = default
# 指定包含环境(总会生效的环境)
spring.profiles.include = dev
一句话总结,生效的环境为激活的环境或默认环境加上包含的环境
配置文件使用Profile功能
application.properties:主配置文件,任何情况下都生效
- application-{profile}.properties可以作为指定环境的配置文件。
- 激活这个环境,配置就会生效。最终生效的所有配置是
- application.properties:主配置文件,任意时候都生效
- application-{profile}.properties:指定环境配置文件,激活指定环境生效
profile优先级 > application
外部化配置
配置优先级
Spring Boot 允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。
我们可以使用各种外部配置源,包括Java Properties文件、YAML文件、环境变量和命令行参数。
@Value可以获取值,也可以用@ConfigurationProperties将所有属性绑定到java object中
以下是 SpringBoot 属性源加载顺序。后面的会覆盖前面的值。由低到高,高优先级配置覆盖低优先级
- 默认属性(通过SpringApplication.setDefaultProperties指定的)
- @PropertySource指定加载的配置(需要写在@Configuration类上才可生效)
- 配置文件(application.properties/yml等)
- RandomValuePropertySource支持的random.*配置(如:@Value(“${random.int}”))
- OS 环境变量
- Java 系统属性(System.getProperties())
- JNDI 属性(来自java:comp/env)
- ServletContext 初始化参数
- ServletConfig 初始化参数
- SPRING_APPLICATION_JSON属性(内置在环境变量或系统属性中的 JSON)
- 命令行参数
- 测试属性。(@SpringBootTest进行测试时指定的属性)
- 测试类@TestPropertySource注解
- Devtools 设置的全局属性。($HOME/.config/spring-boot)
结论:配置可以写到很多位置,常见的优先级顺序:
命令行> 配置文件> springapplication配置
配置文件优先级如下:(后面覆盖前面)
- jar 包内的application.properties/yml
- jar 包内的application-{profile}.properties/yml
- jar 包外的application.properties/yml
- jar 包外的application-{profile}.properties/yml
建议:用一种格式的配置文件。如果.properties和.yml同时存在,则.properties优先
结论:包外 > 包内; 同级情况:profile配置 > application配置
所有参数均可由命令行传入,使用–参数项=参数值,将会被添加到环境变量中,并优先于配置文件。
比如java -jar app.jar --name="Spring"
,可以使用@Value("${name}")
获取
演示场景:
- 包内: application.properties server.port=8000
- 包内: application-dev.properties server.port=9000
- 包外: application.properties server.port=8001
- 包外: application-dev.properties server.port=9001
启动端口?:命令行 > 9001 > 8001 > 9000 > 8000
外部配置
SpringBoot 应用启动时会自动寻找application.properties和application.yaml位置,进行加载。顺序如下:(后面覆盖前面)
- 类路径: 内部
a. 类根路径
b. 类下/config包 - 当前路径(项目所在的位置)
a. 当前路径
b. 当前下/config子目录
c. /config目录的直接子目录
使用spring.config.import可以导入额外配置,额外配置优先级更高
测试
对于组件而言,可以直接使用@Autowired容器中的组件进行测试
class StandardTests {
// 所有单元测试之前执行
@BeforeAll
static void initAll() {
}
// 每个单元测试之前执行
@BeforeEach
void init() {
}
// 为测试类或者测试方法设置展示名称
@DisplayName("tests")
@Test
void succeedingTest() {
}
// 表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
@Test
void failingTest() {
fail("a failing test");
}
@Test
// 测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
@Test
void abortedTest() {
assumeTrue("abc".contains("Z"));
fail("test should have been aborted");
}
// 每个单元测试之后执行
@AfterEach
void tearDown() {
}
// 在所有单元测试之后执行
@AfterAll
static void tearDownAll() {
}
}
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
System.out.println(string);
// 判断给定的布尔值是否为 true
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
@ParameterizedTest
@MethodSource("method") //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
// assertNotNull 判断给定的对象引用是否不为 null
Assertions.assertNotNull(name);
}
static Stream<String> method() {
return Stream.of("apple", "banana");
}