笔记 笔记
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

EasT-Duan

Java 开发
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

购买兑换码请添加

添加时候请写好备注,否则无法通过。

  • Maven

  • Bootstrap

  • Spring

  • Spring MVC

  • MyBatis

  • JUnit

  • GitFlow 工作流指南

  • SpringBoot

    • SpringBoot3-快速入门
    • SpringBoot3-Web开发
    • SpringBoot3-数据访问
    • SpringBoot3-基础特性
      • SpringApplication
        • 自定义 banner
        • 自定义 SpringApplication
        • FluentBuilder API
      • Profiles
        • 使用
        • Profile 分组
        • Profile 配置文件
      • 外部化配置
        • 配置优先级
        • 外部配置
        • 导入配置
        • 属性占位符
      • 单元测试-JUnit5
        • 整合
        • 测试
        • 组件测试
        • 注解
        • 断言
        • 嵌套测试
        • 参数化测试
    • SpringBoot3-核心原理
    • SpringBoot3-场景集成
  • Reactor

  • 微服务

  • Java Web
  • SpringBoot
EasT-Duan
2024-09-05
目录

SpringBoot3-基础特性

欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。

# SpringApplication

# 自定义 banner

  1. 类路径添加 banner.txt 或设置 spring.banner.location 就可以定制 banner
  2. 推荐网站:bootschool (opens new window)

# 自定义 SpringApplication

@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
2
3
4
5
6
7
8

# FluentBuilder API

new SpringApplicationBuilder()
    .sources(Parent.class)
    .child(Application.class)
    .bannerMode(Banner.Mode.OFF)
    .run(args);
1
2
3
4
5

# Profiles

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

步骤:

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

# 使用

  1. 配置激活指定环境(使用配置文件):

在 application.properties 文件中:

spring.profiles.active=production,hsqldb
1

对应的 Java 配置类:

@Configuration
@Profile("production")
public class ProductionConfig {
    @Bean
    public DataSource productionDataSource() {
        // 返回生产环境的数据源
    }
}

@Configuration
@Profile("hsqldb")
public class HsqldbConfig {
    @Bean
    public DataSource hsqldbDataSource() {
        // 返回 HSQLDB 的数据源
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  1. 使用命令行激活环境:

在启动应用时,使用以下命令:

java -jar yourapp.jar --spring.profiles.active=dev,hsqldb
1
  1. 配置默认环境:

在 application.properties 文件中:

spring.profiles.default=test
1

对应的 Java 配置类:

@Configuration
public class DefaultConfig {
    @Bean
    public DataSource defaultDataSource() {
        // 返回默认的数据源
    }
}

@Configuration
@Profile("test")
public class TestConfig {
    @Bean
    public DataSource testDataSource() {
        // 返回测试环境的数据源
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  1. 不使用 @Profile 的组件(永远存在):
@Configuration
public class AlwaysActiveConfig {
    @Bean
    public Logger logger() {
        return LoggerFactory.getLogger(AlwaysActiveConfig.class);
    }
}
1
2
3
4
5
6
7
  1. 推荐使用激活方式激活指定环境:

在 application.properties 文件中:

spring.profiles.active=dev
1

或者在启动时使用命令行参数:

java -jar yourapp.jar --spring.profiles.active=dev
1

对应的 Java 配置类:

@Configuration
@Profile("dev")
public class DevConfig {
    @Bean
    public DataSource devDataSource() {
        // 返回开发环境的数据源
    }
    
    @Bean
    public EmailService devEmailService() {
        return new MockEmailService(); // 开发环境使用模拟邮件服务
    }
}

@Configuration
@Profile("prod")
public class ProdConfig {
    @Bean
    public DataSource prodDataSource() {
        // 返回生产环境的数据源
    }
    
    @Bean
    public EmailService prodEmailService() {
        return new RealEmailService(); // 生产环境使用真实邮件服务
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

最佳实战:

  • 生效的环境 = 激活的环境 / 默认环境 + 包含的环境

  • 项目里面这么用

    • 基础的配置 mybatis 、 log 、 xxx :写到包含环境中
    • 需要动态切换变化的 db 、 redis :写到激活的环境中

# Profile 分组

创建 prod 组,指定包含 db 和 mq 配置

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

使用 --spring.profiles.active=prod ,就会激活 prod,db,mq 配置文件

# Profile 配置文件

application-{profile}.properties 可以作为指定环境的配置文件。

激活这个环境,配置就会生效。最终生效的所有配置是

  • application.properties :主配置文件,任意时候都生效

  • application-{profile}.properties :指定环境配置文件,激活指定环境生效

profile 优先级 > application

# 外部化配置

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

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

# 配置优先级

Spring Boot 允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。

我们可以使用各种外部配置源,包括 Java Properties 文件、YAML 文件、环境变量和命令行参数。

@Value 可以获取值,也可以用 @ConfigurationProperties 将所有属性绑定到 java object 中

以下是 SpringBoot 属性源加载顺序。后面的会覆盖前面的值。由低到高,高优先级配置覆盖低优先级

  1. 默认属性(通过 SpringApplication.setDefaultProperties 指定的)
  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

# 外部配置

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

  1. 类路径:内部

  2. 类根路径

    • 类下 /config 包
  3. 当前路径(项目所在的位置)

  4. 当前路径

    • 当前下 /config 子目录
    • /config 目录的直接子目录

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

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

规律:最外层的最优先。

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

配置不同就都生效(互补),配置相同高优先级覆盖低优先级

# 导入配置

使用 spring.config.import 可以导入额外配置

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

无论以上写法的先后顺序,my.properties 的值总是优先于直接在文件中编写的 my.property。

# 属性占位符

配置文件中可以使用 ${name:default} 形式取出之前配置过的值。

app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
1
2

# 单元测试 - 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>
1
2
3
4
5

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

  • JUnit 5 (opens new window)
  • Spring Test (opens new window)
  • AssertJ (opens new window)
  • Hamcrest (opens new window)
  • Mockito (opens new window)
  • JSONassert (opens new window)
  • JsonPath (opens new window)

# 测试

# 组件测试

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

# 注解

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:为测试类或测试方法提供扩展类引用
public class StandardTests {

    @BeforeAll
    static void initAll() {
    }

    @BeforeEach
    void init() {
    }

    @DisplayName("showthisname")
    @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() {
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 断言

方法 说明
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());
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# 参数化测试

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

static Stream<String> method() {
    return Stream.of("apple", "banana");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
上次更新: 2025/04/12, 05:37:39
SpringBoot3-数据访问
SpringBoot3-核心原理

← SpringBoot3-数据访问 SpringBoot3-核心原理→

最近更新
01
Reactor 核心
02-24
02
前置条件
10-30
03
计算机网络
09-13
更多文章>
Theme by Vdoing | Copyright © 2019-2025 powered by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式