SpringBoot3【④ 基础特性(外部和内部化配置,整合Junit)】

news2024/9/22 7:38:11

1. SpringApplication

1.1. 自定义 banner

  1. 类路径添加banner.txt或设置spring.banner.location就可以定制 banner
  2. 推荐网站:Spring Boot banner 在线生成工具,制作下载英文 banner.txt,修改替换 banner.txt 文字实现自定义,个性化启动 banner-bootschool.net

1.2. 自定义 SpringApplication

在这里插入图片描述
拆开来写可以自定义SpringApplication的行为

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);
    }

}

1.3. FluentBuilder API

流式方式启动SpringApplication

new SpringApplicationBuilder()
    .sources(Parent.class)
    .child(Application.class)
    .bannerMode(Banner.Mode.OFF)
    .run(args);

2. Profiles

环境隔离能力;快速切换开发、测试、生产环境
步骤:

  1. 标识环境:指定哪些组件、配置在哪个环境生效
  2. 切换环境:这个环境对应的所有组件和配置就应该生效

2.1. 使用

2.1.1 指定环境

  • Spring Profiles 提供一种隔离配置的方式,使其仅在特定环境生效;
  • 任何@Component, @Configuration@ConfigurationProperties 可以使用 @Profile 标记,来指定何时被加载。【容器中的组件都可以被 @Profile标记

2.1.2 环境激活

  1. 配置激活指定环境; 配置文件 (IDea 能自动识别我们已经给组件设置的所有环境,并自动提示)
spring.profiles.active=dev,test
  1. 也可以使用命令行激活。java -jar xxxxxxx --spring.profiles.active=dev,test (生产环境在Linux服务器下启动web项目)
  2. 还可以配置默认环境不标注@Profile 的组件永远都存在。
    1. 以前默认环境叫default
    2. 在配置文件可以通过spring.profiles.default=test对默认环境的名字进行更改(不推荐这么做
  3. 推荐使用激活方式激活指定环境

2.1.3 环境包含(不管激活与否都要包含的环境)

注意:

  1. spring.profiles.activespring.profiles.default 只能用到 无 profile 的文件中(即主配置文件),如果在如application-dev.yamlapplication-test.properties中编写就是无效的
  2. 也可以额外添加生效文件,而不是激活替换。比如:
spring.profiles.include[0]=dev
spring.profiles.include[1]=test

配置文件的语法第一节讲过,这么写也行

spring.profiles.include=dev,test

最佳实战:

  • 生效的环境 = 激活的环境/默认环境 + 包含的环境
  • 项目里面这么用
    • 基础的配置mybatislogxxx:写到包含环境中
    • 需要动态切换变化的 dbredis:写到激活的环境中

2.2. Profile 分组

创建prod组,指定包含dbmq配置

spring.profiles.group.prod[0]=db
spring.profiles.group.prod[1]=mq

等同于

spring.profiles.group.prod=db,mq

分组之后,配置文件激活就可以直接激活组名

2.3. Profile 配置文件

  • application-{profile}.properties可以作为指定环境的配置文件
  • 激活这个环境,配置就会生效。最终生效的所有配置是 (仍可以靠主配置文件激活或命令行激活)
    • application.properties:主配置文件,任意时候都生效
    • application-{profile}.properties:指定环境配置文件,激活指定环境生效
      如果发生配置冲突 :profile优先级 > application

3. 外部化配置

场景:线上应用如何快速修改配置,并应用最新配置

  • SpringBoot 使用 配置优先级 + 外部配置 简化配置更新、简化运维。
  • 只需要给jar应用所在的文件夹放一个application.properties最新配置文件,重启项目就能自动应用最新配置

3.1. 配置优先级

Spring Boot 允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。
我们可以使用各种外部配置源,包括Java Properties文件、YAML文件、环境变量命令行参数
@Value可以获取值,也可以用@ConfigurationProperties将所有属性绑定到java object
以下是 SpringBoot 属性源加载顺序后面的会覆盖前面的值。 由低到高,高优先级配置覆盖低优先级

  1. 默认属性(通过SpringApplication.setDefaultProperties指定的,上面第一节流式控制和主程序通过set方法控制都可以
  2. @PropertySource指定加载的配置(需要写在@Configuration类上才可生效)
  3. 配置文件(application.properties/yml等)
  4. RandomValuePropertySource支持的random.*配置(如:@Value(“${random.int}”))
  5. OS 环境变量
  6. Java 系统属性(System.getProperties()
  7. JNDI 属性(来自java:comp/env
  8. ServletContext 初始化参数
  9. ServletConfig 初始化参数
  10. SPRING_APPLICATION_JSON属性(内置在环境变量或系统属性中的 JSON)
  11. 命令行参数
  12. 测试属性。(@SpringBootTest进行测试时指定的属性)
  13. 测试类@TestPropertySource注解
  14. Devtools 设置的全局属性。($HOME/.config/spring-boot)

结论:配置可以写到很多位置,常见的优先级顺序:

  • 命令行 > 配置文件 > springapplication配置

配置文件优先级如下:(后面覆盖前面)

  1. jar 包内application.properties/yml
  2. jar 包内application-{profile}.properties/yml
  3. jar 包外application.properties/yml
  4. 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

3.2. 外部配置

SpringBoot 应用启动时会自动寻找application.propertiesapplication.yaml位置,进行加载。顺序如下:(后面覆盖前面)

  1. 类路径: 内部
    1.1. 类根路径
    1.2. 类下/config
  2. 当前路径(项目所在的位置 -> jar包的目录位置)
    2.1 当前路径
    2.2 当前下/config子目录
    2.3 /config目录的直接子目录

最终效果:优先级由高到低,前面覆盖后面

  • 命令行 > 包外config直接子目录 > 包外config目录 > 包外根目录 > 包内目录
  • 同级比较:
    • profile配置 > 默认配置
    • properties配置 > yaml配置

在这里插入图片描述
规律:最外层的最优先。

  • 命令行 > 所有
  • 包外 > 包内
  • config目录 > 根目录
  • profile > application

配置不同就都生效(互补),配置相同高优先级覆盖低优先级(前提得激活profile)

3.3. 导入配置

使用spring.config.import可以导入额外配置,类似于@PropertySource注解的作用

spring.config.import=my.properties
my.property=value

无论以上写法的先后顺序,my.properties的值总是优先于直接在文件中编写的my.property。即外部的配置总是大于内部的,深层的大于浅层的,profile大于主配置的

3.4. 属性占位符

配置文件中可以使用${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})

4. 单元测试-JUnit5

4.1. 整合

SpringBoot 提供一系列测试工具集及注解方便我们进行测试。
spring-boot-test提供核心测试能力,spring-boot-test-autoconfigure 提供测试的一些自动配置。
我们只需要导入spring-boot-starter-test 即可整合测试
自带@SpringBootTest注解,有了这个注解就能在测试方法通过@AutoWired注入ioc容器任何存在的组件。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

spring-boot-starter-test 默认提供了以下库供我们测试使用

  • JUnit 5
  • Spring Test
  • AssertJ
  • Hamcrest
  • Mockito
  • JSONassert
  • JsonPath

4.2. 测试

4.2.0 组件测试

直接@Autowired容器中的组件进行测试

4.2.1 注解

JUnit5的注解与JUnit4的注解有所变化
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations

  • @Test :表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
  • @ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
  • @RepeatedTest :表示方法可重复执行,下方会有详细介绍
  • @DisplayName :为测试类或者测试方法设置展示名称
  • @BeforeEach :表示在每个单元测试之前执行
  • @AfterEach :表示在每个单元测试之后执行
  • @BeforeAll :表示在所有单元测试之前执行
  • @AfterAll :表示在所有单元测试之后执行
  • @Tag :表示单元测试类别,类似于JUnit4中的@Categories
  • @Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
  • @Timeout :表示测试方法运行如果超过了指定时间将会返回错误
  • @ExtendWith :为测试类或测试方法提供扩展类引用
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() {
    }

}

4.2.2 断言 (Assertions类的静态方法)

方法说明
assertEquals判断两个对象或两个原始类型是否相等
assertNotEquals判断两个对象或两个原始类型是否不相等
assertSame判断两个对象引用是否指向同一个对象
assertNotSame判断两个对象引用是否指向不同的对象
assertTrue判断给定的布尔值是否为 true
assertFalse判断给定的布尔值是否为 false
assertNull判断给定的对象引用是否为 null
assertNotNull判断给定的对象引用是否不为 null
assertArrayEquals 数组断言
assertAll组合断言
assertThrows 异常断言
assertTimeout 超时断言
fail 快速失败

4.2.3 嵌套测试

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());
            }
        }
    }
}

4.2.4 参数化测试

参数化测试是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");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

笔记本没有WIFI列表解决方案

是否有网络图标类似于地球的图案 打开个性化 点击打开或关闭系统图标 查看网络那一项是否是打开 如果没有打开就打开注册表 如果不是上图中的数据&#xff0c;就右键新建输入以上的数据。如果还是不能解决就进行如下操作 打开控制面板&#xff0c;打开网络与Internet,再打…

初出茅庐的小李博客之机智云获取网络实时时间(NTP)

机智云获取网络实时时间 机智云代码中其实这么一个函数gizwitsGetNTP( )可以获取网络时间&#xff0c;今天就在STM32F407上教大家如何通过机智云获取NTP网络时间。 简单介绍一下NTP: 网络时间同步现在有2种同步协议NTP和PTP&#xff0c;NTP与PTP不同在于时间戳的产生位置。N…

Kubernetes对象深入学习之二:细说schema.ObjectKind

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 在前文咱们对对象体系有了大概了解&#xff0c;接下来就要按照前面换分的三个知识区域逐个深入学习&#xff0c;今天从最简单的对象类型开始 runtime.Object…

PWM 输出实验(stm32)

目录 PWM的代码pwm.cpwm.h main.c 说明&#xff1a;以下内容参考正点原子的资料 PWM的代码 pwm.c //TIM3 PWM部分初始化 //PWM输出初始化 //arr&#xff1a;自动重装值 //psc&#xff1a;时钟预分频数 void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitSt…

华为云CodeArts Build-云端化的编译构建平台

随着互联网企业业务种类增多&#xff0c;业务跨平台&#xff0c;多语言编程成为常态。 传统应用软件为本地应用&#xff0c;业务复杂&#xff0c;软件规模大&#xff0c;编译构建耗时长&#xff0c;而且移动终端APP业务变化快&#xff0c;交付要求短平快。 因此一个支持多语言…

环型链表oj

文章目录 题目描述解决方法 题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中…

java 阿里云直播配置及推拉流地址获取

一、开通阿里云直播 首先进入阿里云直播产品主页&#xff1a;https://www.aliyun.com/product/live 。 点击下方的“立即开通”。 如果是还未注册的用户请按照页面提示进行完成注册并实名认证。 2、首次进入会提示开通服务&#xff0c;点击“开通服务”&#xff0c;然后选择计…

[C++] 万字 - C++异常处理分析介绍: 异常概念、异常抛出与捕获匹配原则、重新抛出、异常安全、异常体系...

C语言 错误处理方式 在C语言中, 代码发生错误一般会有两种处理方式: 终止程序. 比如 直接使用assert()断言. 或者直接崩溃 返回、设置错误码 C语言某些函数执行失败, 但是结果不足以导致致命问题时, 就会将错误码设置在errno中. 用户可以通过strerr(errno)来获取错误信息. …

Linux的管道符详解

&#xff08;该图由AI绘制 关注我 学习AI画图&#xff09; 目录 管道&#xff08;重点&#xff09; 1、管道符 2、过滤&#xff08;筛选&#xff09;功能 3、特殊功能&#xff08;了解&#xff09; 4、统计功能&#xff08;重点&#xff09; 5、xargs命令扩展 管道&…

多元分类预测 | Matlab全连接神经网络(DNN)分类预测,多特征输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 全连接神经网络(DNN)分类预测,多特征输入模型 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,程序可出分类效果图,迭代优化图,混淆矩阵图。 部分源码

设计数据库时,字段“是否可用”该取什么英文名?研究active/enable/state/progress的区别

一条记录发布后&#xff0c;除了删除状态&#xff0c;还存在可用、不可用状态&#xff08;并非审核状态&#xff09;&#xff0c;那么这个字段在数据库中该取什么名字呢&#xff1f;先告诉结果&#xff1a;使用active英文单词衍生出的is_active。 表可用 active - 意为活跃或生…

Java经典面试题下包含答案

21.String、StringBuffer和StringBuilder的区别是什么&#xff1f; 线程安全&#xff1a; String中的对象是不可变的&#xff0c;线程安全StringBuffer对方法加了同步锁&#xff0c;所以是线程安全的StringBuilder没有对方法加同步锁&#xff0c;所以是非线程安全的 使用效率…

【STM32单片机】STM32控制SG90舵机的PWM部分参数的设置解答

STM32控制SG90舵机的PWM部分参数的设置解答 一、舵机控制要知道的知识二、PWM的参数要怎么计算1、为什么要分频呢&#xff1f;2、为什么选择TIM_OCMode_PWM1呢&#xff1f; 每天进步一点点 笔记仅供自学&#xff0c;用来回看复习&#xff0c;不一定适合你&#xff0c;如有错误请…

论青春线上书屋的设计与实现(论文+源码)_kaic

目 录 摘 要 III 第一章 绪论 1 1.1本课题研究背景与意义 1 1.2本课题国内外研究现状 1 第二章 开发技术介绍 3 2.1JDK的安装与配置 3 2.2HTML技术 3 2.3MySQL数据库管理系统 4 2.4JDBC的使用 4 第三章 系统分析 5 3.1系统的设计要求 5 3.2系…

交通 | 动态设施选址问题

论文解读 陈迎新&#xff0c;柯斯琪&#xff0c;曲晨辉&#xff0c;张景琪 编者按 本次解读的文章是Transportation Science 2017年的 《在日益增长的市场中&#xff0c;动态设施选址问题的连续逼近方法》&#xff08;Wang, X., Lim, M. K., & Ouyang, Y. (2017). A conti…

空元素不占用位置处理

一. 问题场景&#xff1a; 如果将一个元素的CSS设置为margin-right: 10px&#xff0c;即使这个元素为空&#xff0c;那么这10px依然存在&#xff0c;效果如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…

【编译原理】词法分析程序设计(C语言)

目录 一、实验内容二、实验原理三、结果分析四、源代码一、实验内容 给定下表所示的一个简单语言的词法规则描述完成以下任务: (1)画出识别该语言词法规则的状态转换图; (2)依据状态转换图,设计并编制词法分析程序,实现从输入源程序中,识别出各类单词,即关键字、标识…

打工人如何利用自动化实现职场突围

作为优秀的打工人&#xff0c;如果可以将办公中的重复性、繁琐性、低效性工作自动化&#xff0c;那么将省去许多日常工作。许亚宁就是这样一个优秀的打工人&#xff0c;善于使用各类自动化工具来提升工作效率&#xff0c;上周的直播他分享了如何利用自动化工具&#xff0c;实现…

设计原则-依赖倒置原则

如同人体结构一样&#xff0c;项目代码也是需要有结构的&#xff0c;如原子逻辑块(不可再分代码块)、方法、类、模块等。结构要么是由成熟的框架搭建起来&#xff0c;要么自己手动划分&#xff0c;但是都需要保证下层模块的变动时不会影响上层模块。注意&#xff1a;这里所说的…

missing-semester————2

文章目录 shell 脚本赋值语法函数逻辑运算符命令替换进程替换通配 shell工具查看命令如何使用查找文件查找代码查找shell指令 shell 脚本 很多情况下需要执行一系列的操作并使用条件或循环这样的控制流。 大多数shell都有自己的一套脚本语言&#xff0c;包括变量、控制流和自…