banner.txt
或设置spring.banner.location
就可以定制 banner
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
流式方式启动SpringApplication
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
环境隔离能力;快速切换开发、测试、生产环境
步骤:
- 标识环境:指定哪些组件、配置在哪个环境生效
- 切换环境:这个环境对应的所有组件和配置就应该生效
@Component
, @Configuration
或 @ConfigurationProperties
可以使用 @Profile
标记,来指定何时被加载。【容器中的组件都可以被 @Profile
标记 】spring.profiles.active=dev,test
java -jar xxxxxxx --spring.profiles.active=dev,test
(生产环境在Linux服务器下启动web项目)@Profile
的组件永远都存在。
default
spring.profiles.default=test
对默认环境的名字进行更改(不推荐这么做)注意:
spring.profiles.active
和spring.profiles.default
只能用到 无 profile 的文件中(即主配置文件),如果在如application-dev.yaml
,application-test.properties
中编写就是无效的spring.profiles.include[0]=dev
spring.profiles.include[1]=test
配置文件的语法第一节讲过,这么写也行
spring.profiles.include=dev,test
最佳实战:
mybatis
、log
、xxx
:写到包含环境中db
、redis
:写到激活的环境中创建prod
组,指定包含db
和mq
配置
spring.profiles.group.prod[0]=db
spring.profiles.group.prod[1]=mq
等同于
spring.profiles.group.prod=db,mq
分组之后,配置文件激活就可以直接激活组名
application-{profile}.properties
可以作为指定环境的配置文件。application.properties
:主配置文件,任意时候都生效application-{profile}.properties
:指定环境配置文件,激活指定环境生效场景:线上应用如何快速修改配置,并应用最新配置?
- SpringBoot 使用 配置优先级 + 外部配置 简化配置更新、简化运维。
- 只需要给
jar
应用所在的文件夹放一个application.properties
最新配置文件,重启项目就能自动应用最新配置
Spring Boot 允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。
我们可以使用各种外部配置源,包括Java Properties
文件、YAML
文件、环境变量
和命令行参数
。
@Value
可以获取值,也可以用@ConfigurationProperties
将所有属性绑定到java object
中
以下是 SpringBoot 属性源加载顺序。后面的会覆盖前面的值。 由低到高,高优先级配置覆盖低优先级
SpringApplication.setDefaultProperties
指定的,上面第一节流式控制和主程序通过set方法控制都可以)@PropertySource
指定加载的配置(需要写在@Configuration
类上才可生效)RandomValuePropertySource
支持的random.*
配置(如:@Value(“${random.int}”))System.getProperties()
)java:comp/env
)ServletContext
初始化参数ServletConfig
初始化参数SPRING_APPLICATION_JSON
属性(内置在环境变量或系统属性中的 JSON)@SpringBootTest
进行测试时指定的属性)@TestPropertySource
注解$HOME/.config/spring-boot
)结论:配置可以写到很多位置,常见的优先级顺序:
命令行
>配置文件
>springapplication配置
配置文件优先级如下:(后面覆盖前面)
application.properties/yml
application-{profile}.properties/yml
application.properties/yml
application-{profile}.properties/yml
.properties
和.yml
同时存在,则.properties
优先结论:
包外 > 包内
; 同级情况:profile配置 > application配置
所有参数均可由命令行传入,使用--参数项=参数值
,将会被添加到环境变量中,并优先于配置文件
。
比如java -jar app.jar --name="Spring"
,可以使用@Value("${name}")
获取
演示场景:
server.port=8000
server.port=9000
server.port=8001
server.port=9001
9001
> 8001
> 9000
> 8000
SpringBoot 应用启动时会自动寻找application.properties
和application.yaml
位置,进行加载。顺序如下:(后面覆盖前面)
/config
包/config
子目录/config
目录的直接子目录最终效果:优先级由高到低,前面覆盖后面
规律:最外层的最优先。
配置不同就都生效(互补),配置相同高优先级覆盖低优先级(前提得激活profile)
使用spring.config.import
可以导入额外配置,类似于@PropertySource
注解的作用
spring.config.import=my.properties
my.property=value
无论以上写法的先后顺序,my.properties
的值总是优先于直接在文件中编写的my.property
。即外部的配置总是大于内部的,深层的大于浅层的,profile大于主配置的
配置文件中可以使用${name:default}
形式取出之前配置过的值。
app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
然后在Controller
中可以设置私有属性private String xxx;
,通过 @Value("${app.description}")
注入属性
如果配置文件没有这个属性值,会报错,为了防止报错的问题出现,可以加:xxx,相当于没有的情况下赋值默认值: @Value(${app.name:DefaultApp})
SpringBoot 提供一系列测试工具集及注解方便我们进行测试。
spring-boot-test
提供核心测试能力,spring-boot-test-autoconfigure
提供测试的一些自动配置。
我们只需要导入spring-boot-starter-test
即可整合测试
自带@SpringBootTest
注解,有了这个注解就能在测试方法通过@AutoWired
注入ioc容器任何存在的组件。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
spring-boot-starter-test 默认提供了以下库供我们测试使用
直接@Autowired
容器中的组件进行测试
JUnit5的注解与JUnit4的注解有所变化
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class StandardTests {
@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
}
@DisplayName("")
@Test
void succeedingTest() {
}
@Test
void failingTest() {
fail("a failing test");
}
@Test
@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() {
}
}
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
assertArrayEquals | 数组断言 |
assertAll | 组合断言 |
assertThrows | 异常断言 |
assertTimeout | 超时断言 |
fail | 快速失败 |
JUnit 5 可以通过 Java 中的内部类和
@Nested
注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach
和@AfterEach
注解,而且嵌套的层次没有限制。
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, stack::pop);
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, stack::peek);
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用 @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);
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
@ParameterizedTest
@MethodSource("method") //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}
// 返回Stream即可
static Stream<String> method() {
return Stream.of("apple", "banana");
}