SpringBoot3基础特性
SpringApplication
自定义banner
- 类路径添加banner.txt或设置spring.banner.location就可以定制banner
- 推荐网站:Spring Boot banner在线生成工具,制作下载英文banner.txt,修改替换banner.txt文字实现自定义。
提示:
可以通过修改配置文件application.properties配置文件来关闭banner。
spring.main.banner-mode=off
自定义SpringApplication
@SpringBootApplication
public class Boot311Application {
public static void main(String[] args) {
//SpringApplication:Boot应用的核心API入口
//SpringApplication.run(Boot311Application.class, args);
//1、自定义SpringApplication的底层设置
SpringApplication springApplication = new SpringApplication(Boot311Application.class);
//调整SpringApplication的参数
//和配置文件设置冲突时,会优先配置文件
springApplication.setBannerMode(Banner.Mode.CONSOLE);
//2、SpringApplication运行
springApplication.run(args);
}
}
FluentBuilder API
//Builder方式构造SpringApplication
new SpringApplicationBuilder()
.main(Boot311Application.class)
.bannerMode(Banner.Mode.CONSOLE)
.sources(Boot311Application.class)
.run(args);
Profiles
环境隔离能力,快速切换开发、测试、生产环境
实现步骤
- 标识环境:指定哪些组件、配置在什么时候生效
- 切换环境:这个环境对应的所有组件和配置就应该生效
①、指定环境
Spring Profiles提供一种隔离配置的方式,使其仅在特定环境生效,任何@Component,@Configuration或@ConfigurationProperties可以使用@Profile标记,来指定何时被加载(容器中的组件都可以被@Profile标记)。
②、环境激活
使用修改配置文件application.properties方式激活。
spring.profiles.active=dev,test
测试
创建四个组件Cat、Dog、Pig和Sheep。
Cat
@Data
@Component
@Profile({"dev", "test"})
public class Cat {
private String name;
private String color;
}
Dog
@Component
@Data
@Profile("test")
public class Dog {
private String name;
private String age;
}
Pig
@Component
@Data
@Profile({"prod"})
public class Pig {
private Integer id;
private String name;
}
Sheep
@Component
@Data
public class Sheep {
private Long id;
private String name;
private Integer age;
}
测试及结果
@Slf4j
@SpringBootApplication
public class Boot311Application {
public static void main(String[] args) {
//Builder方式构造SpringApplication
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.main(Boot311Application.class)
.bannerMode(Banner.Mode.CONSOLE)
.sources(Boot311Application.class)
.run(args);
try {
//由于在没有找到的情况下会抛异常
Cat cat = context.getBean(Cat.class);
log.info("组件cat:{}", cat);
}catch (Exception e){
}
try {
Dog dog = context.getBean(Dog.class);
log.info("组件dog:{}", dog);
}catch (Exception e){
}
try {
Pig pig = context.getBean(Pig.class);
log.info("组件pig:{}", pig);
}catch (Exception e){
}
try {
Sheep sheep = context.getBean(Sheep.class);
log.info("组件sheep:{}", sheep);
}catch (Exception e){
}
}
}
/**
* 1、标识环境
* 1) dev(开发环境)、test(测试环境)、prod(生产环境)、default(在没有设置激活时会生效,但设置激活不是default时不会生效)
* 组件没有标注@Profile代表任意时候都生效
* 2) 指定每个组件在哪个环境下生效
* @Profile({"dev", "test"})
* 3) 默认只有激活指定环境,这些组件才会生效
* 结果;组件sheep:Sheep(id=null, name=null, age=null)
* 2、激活环境
* 1)使用配置文件:spring.profiles.active=dev,test
* 结果:
* 组件cat:Cat(name=null, color=null)
* 组件dog:Dog{name='null', age='null'}
* 组件sheep:Sheep(id=null, name=null, age=null)
* 2)命令行激活:java -jar xxx.jar --spring.profile.active=dev
*/
③、环境包含
Spring.profiles.active和spring.profiles.default属性用于配置和激活不同环境下的配置文件。通常情况下,这些属性应该在专门用于配置环境的文件中进行设置,而不是在application-dev.yaml这样的具体环境文件中。也可以额外添加生效文件(表示不管激活哪个环境,这个包含的环境都要有。即总是要生效的环境。),而不是激活文件。比如:
spring.profiles.include[0]=common
spring.profiles.include[1]=local
总结:
生效的环境 = 激活的环境 + 默认环境(没有添加@Profile) + 包含的环境.
项目中使用:
基础的配置:mybatis、log…:写到(include)包含环境中
需要动态切换变换的环境:db、redis:写到激活环境,可以使用spring.profiles.group.xxx=dev, test进行分组,只需要激活xxx
就可以将分组中的内容全部激活。
Profile配置文件
- application-{profile}.properties可以作为指定环境的配置文件。
- 激活这个环境,配置就会生效。最终生效的所有配置是:
application.properties:主配置文件,任意时候都生效
application-{profile}.properties:指定环境配置文件,激活指定环境生效。
例如:
在application.properties文件中添加配置。
spring.profiles.active=dev
表示在激活dev环境的时候配置文件application-dev.properties生效。
注意:
①、当激活的配置文件内容和主配置文件冲突时,以激活的为主。
②、项目的所有生效配置项 = 激活环境配置文件的所有项 + 主配置文件不冲突的所有项
多环境并发控制
除了SpringBoot外很多的构建工具都有多环境的情况,如:Maven、SpringBoot,如果两者都配置并且它们的环境不同,应该以先加载的环境为主。
a、当maven与SpringBoot同时对多环境进行控制时,以Mven为主,SpringBoot使用@maven中activ标签名称@占位符读取Maven对应的配置属性
b、基于SpringBoot读取Maven配置属性的前提下,如果在Idea下测试工程时,pom.xml每次更新需要手动compile方可生效。
示例:
在pom.xml中,我们可以使用Maven的profiles来定义这些不同的环境配置。
<profiles>
<profile>
<id>dev</id>
<properties>
<db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
<db.username>dev_user</db.username>
<db.password>dev_password</db.password>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<db.url>jdbc:mysql://localhost:3306/prod_db</db.url>
<db.username>prod_user</db.username>
<db.password>prod_password</db.password>
</properties>
</profile>
</profiles>
在Spring Boot的配置文件application.properties中,使用@maven注解来读取Maven配置文件中定义的属性。
spring.datasource.url=@maven.db.url@
spring.datasource.username=@maven.db.username@
spring.datasource.password=@maven.db.password@
外部化配置
场景:线上应用如何快速修改配置,并应用最新配置?
- SpringBoot使用配置优先级 + 外部配置简化配置、简化运维
- 只需要给jar应用所的文件夹放一个application.properties最新配置文件,重启项目就能自动应用最新配置。
配置优先级
SpringBoot允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。我们可以使用各种外部配置源,包括Java Properties文件,YAML文件、环境变量和命令行参数。@Value可以获取值,也可以用@ConfiguraionProperties将所有属性绑定到java object中。
以下是SpringBoot属性源加载顺序(优先级由低到高,高优先级配置会覆盖低优先级。),后面的会覆盖前面的值。
- 默认属性( spring.application.setDefaultProperties指定)
- @PropertySource指定加载的配置(需要写在@Configuration类上才生效)
- 配置文件(application.properties/yaml等)
- RandomValuePropertySource支持的random.*配置(如:@Value(“${random.int}”))
- OS环境变量
- Java系统属性(来自System.Properties())
- JNDI属性(来自java:comp/env)
- ServletContext初始化参数
- ServletConfig初始化参数
- SPRING_APPLICATION_JSON属性(内置在环境变量或系统属性中的JSON)
- 命令行参数
- 测试属性。(@SpringBootTest进行测试时指定的属性)
- 测试类@TestPropertySource注解
- Devtoos设置的全局属性。($HOME/.config/spring-boot)
结论:
配置可以写道很多位置,常见的优先级顺序:命令行>配置文件>springapplication配置
配置文件优先级如下(从低到高):
- jar包内的application.properties/yaml
- jar包内的application-{profile}.properties/yaml
- jar包外的application.propeterties/yaml
- jar包外的application-{profile}.properties/yaml
结论:包外>包内
建议:
①、使用一种格式的配置文件,如果.properties和.yaml同时存在,则.properties优先。
②、所有参数均可由命令行传入,使用–参数项=参数值,例如:–property=value,将会被添加到环境变量中,并优先于配置文件,比如java -jar app.jar --name = “spring”,可以使用@Value(“${name}”)获取。
外部配置
SpringBoot应用启动时会自动寻找application.properties和application.yaml位置进行加载。优先级从低到高如下:
类路径(内部)
- 类根路径
- 类下/config包
当前路径(项目所在的位置,外部)
- 当前路径
- 当前/config子目录
- /config目录的直接子目录
总结
- 命令行>所有
- 包外>包内
- config目录>根目录
- profile>application
配置不同就都生效(部署),配置相同高优先级覆盖低优先级。
导入配置
在配置文件中使用如下配置:
spring.config.import=classpath:/xxx.properties
它和使用@PropertySource效果相同。
注意:配置文件的优先级高于导入配置的优先级。
属性占位符
配置文件中可以使用${name:default}形式取出之前配置过的值
app.name=MyApp
app.description = ${app.name}是我的名字
示例:
application.properties
hello.test= this is my test
控制器
@RestController
public class HelloController {
@Value("${hello.test:1433223}")
String test;
@GetMapping("/hello")
public String test(){
return test;
}
}
单元测试-JUnit5
整合
SpringBoot提供一系列测试工具及注解方便我们进行测试。
spring-boot-test提供核心测试能力,spring-boot-test-autoconfigure提供测试的一些自动配置。只需要导入spring-boot-starter-test即可整合测试。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
spring-boot-starter-test默认提供的测试库有:JUnit5、Spring Test、AssertJ、Hamcrest、Mockito、JSONassert、JsonPath
测试
组件测试
直接使用@Autowired容器中的组件进行测试
示例
创建HelloService
@Service
public class HelloService {
public int sum(int a, int b){
return a+b;
}
}
在测试类中测试
//测试类也必须在主程序所在的包及其子包
@SpringBootTest//具备测试SpringBoot应用容器中所有组件的功能
class Boot311ApplicationTests {
//测试方法
@Autowired//自动注入任意组件即可测试
HelloService helloService;
@Test
void contextLoads() {
int sum = helloService.sum(2, 5);
System.out.println("sum = " + sum);
}
/*sum = 7*/
}
注解
JUnit5的注解与JUnit4注解有所变化
官方文档
参数化测试:
使得用不同的参数多次运行测试成为了可能,为单元测试带来了便利。
利用@ValueSource等注解,指定入参, 可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,减少了代码冗余。
@ValueSource #为参数化测试制定了入参来源,支持八大基本类型以及String类型和Class类型。
@NullSource #表示为参数化测试提供一个null得入参
@EnumSource #表示为参数化测试提供一个枚举入参
@CsvFileSource #表示读取指定CSV文件内容作为参数化测试入参
@MethodSource #表示读取指定方法的返回值作为参数化限额是入参(方法返回需要是一个流)
示例
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试")
public void parameterizedTest1(String string){
System.out.println(string);
//使用断言方式
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
/*
* one
two
three
* */