手动实践过程

20210723

  1. 目标,常规使用
    1. 搭建
    2. 数据库
    3. 常用注解说明

一共有以下简便学习步骤:

  1. 运行样例,先跑起来
  2. 使用其开发/写代码
  3. 运行,测试代码
  4. 打包上线
  5. 高级操作

这次主要学习 Spring 相关内容,中间遇到的一些其他知识点,先记录到另外的文件中,然后回头学习。

首先要明白,
Spring Boot 是创建基于 Spring 的应用程序的工具

下面两句话,可以说明:在 官方文档 Getting Started 章节

Spring Boot 帮助我们创建可独立运行的,生产级的基于 Spring 的应用程序

大多数 Spring Boot 应用程序只需要很少的 Spring 配置,

Spring Boot的依赖项使用org.springframework.boot groupId。通常,你的Maven POM文件继承自spring-boot-starter-parent项目,并声明对一个或多个”Starters”的依赖。Spring Boot还提供了一个可选的Maven插件来创建可执行的jar。

spring.io网站上 Spring Boot 的 “入门” 指南 的作用

spring.io网站上有许多使用Spring Boot的 “入门” 指南。如果你需要解决一个特定的问题,请先在那里查看。

  1. 核心原则

mvn 项目

  • compile,所有编译(compile)后的class文件,都在target/classes 目录下
  • package, 会执行编译,运行test,打包文件 放在 target 目录下
  • install,会执行compile,test,package,然后copy target目录下的jar/war包到本地repo下,可供其他程序使用。

问题:

<dependencyManagement>标签在pom中的作用是什么?
为什么不依赖 spring-boot-starter-parent 就需要向 <dependencyManagement> 这个依赖管理添加内容?

Spring Boot Reference Document 官方参考文档

Using Spring Boot Build Systems, Structuring Your Code, Configuration, Spring Beans and Dependency Injection, DevTools, and more.

Spring Boot Features Profiles, Logging, Security, Caching, Spring Integration, Testing, and more.

官方文档写的特定,与自学视频中总结的不太一样,看看是不是出发点不同

Spring Boot 的四大特性

  • 自动配置 - Auto Configuration
  • 起步依赖 - Starter Dependency
  • 命令行界面 - Spring Boot CLI
  • Actuator

第一个样例程序,注解说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14

@SpringBootApplication
@RestController
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@GetMapping("/hello") // 告诉 Spring 使用 hello() 方法响应发送到 xxx/hello 这个地址的请求
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
1
2
@GetMapping("/hello")  // 告诉 Spring 使用 hello() 方法响应发送到 xxx/hello 这个地址的请求。
@RequestParam(value = "name", defaultValue = "World") // 告诉 Spring 允许在 hello 这个请求后面添加 ?name=xxx 的参数,因为是 Get 请求,所以参数前需要使用 ? 符号将请求路径与参数分隔。

spring-boot-starter-parent 本身没有提供任何依赖

在我们 Sprint Boot 项目的POM文件中,The spring-boot-starter-parent is a special starter that provides useful Maven defaults. It also provides a dependency-management section so that you can omit version tags for “blessed” dependencies.

总的来说就是,spring-boot-starter-parent 也是一个starter,只不过他本身没有提供具体的依赖包,而是提供了一个用来管理版本号的内容,依赖它的POM文件中就可以省掉 spring 相关的版本号了。

具体的依赖都在 spring-boot-starter-xxx 中,例如 spring-boot-starter-web, 那么问题:如果有多个starter中依赖了相同版本的包,是自动排除多余的吗?如果依赖了同一个包的不同版本,会怎么样?还是 spring 中同一个版本的starter 中依赖的包都是同一个版本?这需要测试一下。

常用注解说明:

被称为stereotype注解

它为阅读代码的人和Spring提供了提示,说明这个类扮演了一个特定的角色。

类级注解

@SpringBootApplication 用在Main方法类上,包含三个功能,(所以当不想使用 @SpringBootApplication 注解时,也可以使用下面三个注解的组合代替)

  • @EnableAutoConfiguration ,启用Spring Boot 的自动配置机制

  • @ComponentScan ,对应用程序所在的软件包启用@Component扫描,最佳实践是将主Main类放到根包下(即包的根目录下),然后即可以对该类所在的包目录,及其子目录进行 Bean 扫描。

  • @SpringBootConfiguration ,允许在上下文中注册额外的 bean 或导入其他配置类

    这是 Spring 标准 @Configuration 的替代方案,有助于在你的集成测试中进行配置检测。在 Spring Boot-2.1.1RELEASE 即之前的版本中,使用的是 @Configuration

样例参考 使用 SpringBootApplication 注解

@Controller 告诉 Spring 这是一个 Web 的endpoint(端点),处理传入的 Web 请求时,会解析这个注解标注的类

@RestController 注解告诉Spring将结果字符串直接呈现给调用者。

The @RestController annotation tells Spring to render the resulting string directly back to the caller.

render 用在前端,一般指渲染的意思,但是在 Spring 中翻译为 呈现更合适。

@ComponentScan 查找项目配置的 bean

@Autowired 进行构造函数注入,标记你希望 Spring 使用的哪个构造函数。(没用@Autowired 标注的构造函数怎么办?)

@Component

如果按照上面的建议构造代码(将应用程序类放在根包中),则可以添加 @ComponentScan 而没有任何参数。您的所有应用程序组件( @Component@Service@Repository@Controller 等)都会自动注册为 Spring Bean。

@EnableAutoConfiguration 注解

  • 参考笔记中的了解自动配置的实现原理章节内容,知道自动配置做了哪些事情?怎么做得?如何定制化我们自己的自动配置,并让 Spring Boot 来加载

方法级注解

@RequestMapping 注解,提供了 “路由”信息。它告诉Spring,任何带有 xxx 路径的HTTP请求都应该被映射到它标注的方法中。

常用组合

第六章,使用 Spring Boot

@RequestMapping 注解,提供了 “路由”信息。它告诉Spring,任何带有 xxx 路径的HTTP请求都应该被映射到它标注的方法中。

1
2
3
4
@RequestMapping("/")   // 这里表示任何带有 / 路径的http请求都应该被映射到 home() 方法中
String home() {
return "Hello World!";
}

@RestController和@RequestMapping注解是Spring MVC注解(它们不是Spring Boot特有的)。

为什么 main 方法中需要传入 main 方法所在的类名?

答: We need to pass MyApplication.class as an argument to the run method to tell SpringApplication which is the primary Spring component.

我们需要将MyApplication.class作为参数传递给run方法,以告诉SpringApplication哪个是主要的Spring组件。

Spring Boot 的 Dependency Management

每个 Spring Boot 版本都提供了它支持的精选依赖列表。

您仍然可以指定版本,并在需要时覆盖 Spring Boot 的建议。

精选列表包含了所有可以在Spring Boot中使用的Spring模块,以及第三方库列表。该列表以标准材料清单的形式提供(spring-boot-dependencies),可用于Maven和Gradle。

spring-boot-dependenciesspring-boot-starter-parent POM 中作为 parent 部分被依赖,所以当使用 spring-boot-starter-parent 依赖时,这些都会被我们的项目自动继承。

如果要修改某个依赖库的版本,直接再 pom.xml 中添加 相关依赖版本的 属性

例如:

1
2
3
<properties>
<spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
</properties>

注: 在 spring-boot-dependencies pom上查看受支持的属性的列表。

关于在 Maven 中配置并使用 Spring Boot 相关内容总结:

  • 使用 spring-boot-starter-parent 依赖的时候
  • 不适用 spring-boot-starter-parent 依赖的时候
  1. 一般情况,自己项目的 POM 中可以直接依赖 spring-boot-starter-parent 项目的 POM,这样会继承很多 Spring Boot 处理好的默认项,
  2. 但是如果有其他 父级 POM 需要依赖,或者不想直接依赖 spring-boot-starter-parent,为了保留 Spring Boot 的依赖管理的好处,可以在 项目的 POM 中添加 ,然后将 spring-boot-dependencies 依赖进来,并且设置 scope=import
  3. 当需要修改或者覆盖 spring-boot-dependencies 提供的默认依赖版本时,将新版本的信息,添加到 中,并且放在 spring-boot-dependencies 依赖信息之前即可。

样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencyManagement>
<dependencies>
<!-- Override Spring Data release train provided by Spring Boot -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Fowler-SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Starters

Starters 是一组方便在项目中引用的依赖描述符( dependency descriptors),通过 starter ,我们可以方便的获取 Spring 和相关技术的一站式服务。

Starters 的背景,为什么会存在 Starters ?

传统 Maven 项目的缺点:

构建代码 Struct code

1. 命名 Java 软件包(package)

- 使用 Java 建议的包命令约定,并使用反向域名(例如:`com.example.project`)

2. Main 方法类的位置

- 通常将包含 Main 方法的类,放在包的根目录下
    > 通常我们会将 `@SpringBootApplication` 注解放在有 main 方法的主类上,放在根包中(包的根目录),有利于程序进行组件扫描。

下面列出了一个典型的布局。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
com
+- example
+- myapplication
+- MyApplication.java // 包含 main 方法的主类
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java

3. Configuration 类

从官方文档中暂时还不太懂这部分,这部分具体怎么使用需要看后面的文档

这里涉及一个 @Configuration 注解

Spring Boot 支持 Java-based 配置(基于 Java 的配置),同时也支持将 SpringApplication 与 XML 源一起使用,但是建议我们的主源为单个 @Configuration

支持导入其他配置类

您无需将所有@Configuration都放在一个类中。 @Import注解可用于导入其他配置类。另外,您可以使用@ComponentScan自动拾取所有 Spring 组件,包括@Configuration类。

支持导入 XML 配置

如果绝对必须使用基于 XML 的配置,我们建议您仍然从@Configuration类开始。然后,您可以使用@ImportResource注解来加载 XML 配置文件。

4. Auto-configuration

这部分内容可以参考 极客时间的视频+笔记 69,70 课

Spring Boot自动配置试图根据你所添加的jar依赖项自动配置你的Spring应用程序。

例如,如果HSQLDB在你的classpath上,而且你没有手动配置任何数据库连接Bean,那么Spring Boot就会自动配置内存数据库。

1. 使用自动配置

你只需要在 @Configuration 类中,添加 @EnableAutoConfiguration@SpringBootApplication 两个注解中的一个即可,从而选择加入自动配置。

2. 定制自己的自动配置并替换

3. 禁用指定的 Auto-configuration

如果发现正在应用不需要的特定自动配置类,

  1. 可以通过使用 @EnableAutoConfiguration@SpringBootApplication 注解的 exclude 属性,指定自动配置类的类名,来禁用它
  2. 如果该类不在 classpath 上,你可以使用注解的 excludeName 属性并指定完全合格的名称来代替。

例如:

1
2
3
4
5
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {

}

Spring Bean 和依赖注入

问题:依赖注入的目的是什么?与使用普通的 import 方式有什么不同?

我们建议使用 @ComponentScan (查找您的 bean)和使用 @Autowired (进行构造函数注入)。

如果按照上面的建议构造代码(将应用程序类放在根包中),则可以添加 @ComponentScan 而没有任何参数。您的所有应用程序组件( @Component@Service@Repository@Controller 等)都会自动注册为 Spring Bean。

注:

  1. 如果一个 Bean 有多个构造函数,你需要用 @Autowired 来标记你希望 Spring 使用的哪个。如果只有一个构造函数,则可以省略 @Autowired 注解

例如:下面的例子显示了一个 @ServiceBean,它使用构造函数注入来获得一个所需的 RiskAssessorBean 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.stereotype.Service;

@Service
public class MyAccountService implements AccountService {

private final RiskAssessor riskAssessor;

public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}

// ...

}

如果一个 Bean 有多个构造函数,你需要用 @Autowired 来标记你希望 Spring 使用的那个。

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
import java.io.PrintStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyAccountService implements AccountService {

private final RiskAssessor riskAssessor;

private final PrintStream out;

@Autowired
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
this.out = System.out;
}

public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
this.riskAssessor = riskAssessor;
this.out = out;
}

// ...

}

使用 SpringBootApplication 注解

参考 常用注解说明

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // same as @SpringBootConfiguration @EnableAutoConfiguration
// @ComponentScan
public class MyApplication {

public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}

}

上面的样例中 @SpringBootApplication 注解也可以用三个单一功能的注解的组合代替

所以具体如何使用完全自由决定,,

如果你不希望在你的应用程序中使用组件扫描(component scan)或配置属性扫描(configuration properties scan)。

也可以使用向下面例子用的组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;

@SpringBootConfiguration(proxyBeanMethods = false) // 在之前版本中这里使用 `@Configuration` , `@ConfigurationProperties`-注解的类可以被自动检测到
@EnableAutoConfiguration
@Import({ SomeConfiguration.class, AnotherConfiguration.class }) // 这里使用了 `@Import` 显示导入指定 Bean,代替了 `@ComponentScan` 自动检测所有` @Component`-annotated 类
public class MyApplication {

public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}

}

在此示例中,Application 就像其他任何 Spring Boot 应用程序一样,除了不会自动检测到标有 @Component-注解的类和@ConfigurationProperties-注解的类,并且显式导入用户定义的 Bean (请参阅 @Import)。

运行程序

几种方式

  • IDE 中导入并运行
  • 打成 jar 包执行
    • 可执行 jar 包,通过 java -jar xxx/xxx.jar

      同时执行开启远程调式功能

      1
      2
       $ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
      -jar target/myapplication-0.0.1-SNAPSHOT.jar
    • 使用普通的 classpath + jar 的方式运行
  • 使用 maven 和 gradle 插件运行
  • 热插拔

    由于Spring Boot应用程序是普通的Java应用程序,JVM热部署应该可以开箱即用。JVM热部署所能替换的字节码有一定的限制。要获得更完整的解决方案,可以使用 JRebel

    spring-boot-devtools 模块还包括对快速重启应用程序的支持。详情请见 “How-to”章节的热插拔

Developer Tools

这部分之后再回来重新看

有以下几个功能

  1. 属性默认值
  2. 自动重启
    1. 记录条件评估中的更改
    2. 排除资源
    3. 注意其他路径
    4. 禁用重启
    5. 使用触发文件
    6. 自定义重启类加载器
    7. 已知限制
  3. LiveReload
  4. 全局设置
  5. 远程应用程序

Spring Boot Features

1.1. 启动失败

如果你的应用程序启动失败,注册的 FailureAnalyzers 有机会提供专门的错误信息和具体的行动来解决这个问题。

如果你通过使用java -jar运行你的应用程序,你可以启用debug属性,如下所示。

1
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

1.7. 应用程序事件和侦听器

在内部,Spring Boot 使用事件来处理各种任务。你通常不需要使用应用程序事件,但知道它们的存在会很方便。

当你的应用程序运行时,应用程序事件按以下顺序发送:

这部分也查看官方文档

Application events是通过使用Spring框架的事件发布机制来发送的。

1.8. Web 环境

SpringApplication 试图帮你创建正确类型的 ApplicationContext 。用于确定 WebApplicationType 的算法如下:

  • 如果 Spring MVC 存在,就会使用 AnnotationConfigServletWebServerApplicationContext
  • 如果 Spring MVC 不存在而 Spring WebFlux 存在,则使用 AnnotationConfigReactiveWebServerApplicationContext
  • 否则,将使用 AnnotationConfigApplicationContext

这意味着,如果你在同一个应用程序中使用 Spring MVC 和 Spring WebFlux 的新 WebClient,将默认使用 Spring MVC。你可以通过调用 setWebApplicationType(WebApplicationType) 轻松覆盖。

也可以通过调用 setApplicationContextClass(..) 来完全控制使用的 ApplicationContext 类型。

当在 JUnit 测试中使用 SpringApplication 时,通常需要调用 setWebApplicationType(WebApplicationType.NONE)

1.9. 访问 Application 参数

// do something…

1.10. 使用 ApplicationRunner 或者 CommandLineRunner

使用场景:当你需要在 SpringApplication 启动后,但在其开始接受访问之前运行一些代码/任务,可以使用下面的接口定义 Runner Bean:

  • ApplicationRunner

    • run(ApplicationArguments args) ,参数为 ApplicationArguments
  • CommandLineRunner

    • run(String... args) ,参数为 String[]

异同:

  • 相同点:两个接口,工作方式相同,
  • 不同点:接受参数方式不同,参考上面 run 的传参

使用方式:

  • 实现接口提供的 run 方法,并定义为 Bean (交给 Spring 管理)

    该方法会在 SpringApplication.run(...) 完成之前被调用。

    注:在 SpringApplication 的 public ConfigurableApplicationContext run(String... args) 方法中

    callRunners(context, applicationArguments); // 调用 所有的 Runner 接口实现

  • 这就有两种方式,一种使用 @Component 作用在实现接口的类上,定义为 Bean,

  • 另一种,使用 @Bean 注解,在配置类中定义返回 Bean 的方法。

如果定义了多个Runner Bean (CommandLineRunner 或 ApplicationRunner),可以通过添加 @Order 注解,或者实现 org.springframework.core.Ordered 接口来指定运行顺序

样例:方法一,创建实现接口的类,并标注为 Bean

1
2
3
4
5
6
7
@Component
public class CLRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// do something...
}
}

样例2:使用 @Bean ,定义返回 Bean 的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Bean  
public CommandLineRunner demo2() {

return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {

}
};
}

这里也可以使用 lambda表达式来处理
@Bean
public CommandLineRunner demo2() {
return args -> {
// do something...
};
}

1.11. 程序退出

https://docs.spring.io/spring-boot/docs/2.5.3/reference/html/features.html#features.spring-application.application-exit

从1.8~1.11 这四个子章节的内容与 极客时间的《82 编写命令行运行的程序》内容差不多,再看时,可以考虑两个集合在一起。

1.13. 应用程序启动跟踪

在应用启动期间,SpringApplicationApplicationContext 执行许多与应用生命周期、Bean 生命周期,甚至处理应用事件有关的任务。通过 ApplicationStartup,Spring 框架允许你用 StartupStep 对象跟踪应用程序的启动顺序。这些数据可以为分析目的而收集,或者只是为了更好地了解应用程序的启动过程。

具体使用参考官方文档 应用程序启动跟踪

2. 外化配置

极客时间的 73,74两节内容,与这部分有关联,再深入看时,可以结合在一起看。

2.5.3 版本,这部分写的顺序更容易理解,2.1.1-RELEASE 版本中写的可能让新手容易混淆。

https://docs.spring.io/spring-boot/docs/2.5.3/reference/html/features.html#features.external-config

Spring Boot让你将配置外部化,这样你就可以在不同的环境中使用相同的应用程序代码。你可以使用各种外部配置源,包括Java properties文件、YAML文件、环境变量和命令行参数。

属性值可以通过使用 @Value 注解直接注入你的Bean,通过Spring的 Environment 抽象访问,或者通过 @ConfigurationProperties 绑定到结构化对象

PropertySource 加载和生效顺序

Spring Boot 的 PropertySource 顺序,旨在合理的覆盖值。属性是按照以下顺序考虑。

(后面读取的项目值会覆盖前面读取的相同项目值)

  1. 默认属性(通过设置 SpringApplication.setDefaultProperties 指定)。

  2. @Configuration 类上的 @PropertySource 注解。请注意,这样的属性源直到 application context 被刷新时才会被添加到环境中。这对于配置某些属性来说已经太晚了,比如 logging.*spring.main.* ,它们在刷新开始前就已经被读取了。

  3. 配置文件(如 application.properties 文件)。

    1. 打包在你的 jar 里面(application.properties 和 YAML 变体 .yml)。
    2. 打包在你的jar中(application-{profile}.properties和YAML变量)。
    3. 在你打包的jar之外(application.properties和YAML变体)。
    4. 在你打包的jar之外(application-{profile}.properties和YAML变体)。

      建议你在整个应用程序中坚持使用一种格式。如果你在同一地点有 .properties.yml格式的配置文件,.properties优先。

  4. 一个 RandomValuePropertySource ,它的属性只有 random.*

  5. 操作系统环境变量。

  6. Java 系统属性(System.getProperties()),java -D 参数指定的属性,在命令行中可以通过 -D 参数来指定一些系统属性。

  7. 来自 java:comp/env 的 JNDI 属性。

  8. ServletContext 初始参数。

  9. ServletConfig 初始参数。

  10. 来自 SPRING_APPLICATION_JSON 的属性(嵌入环境变量或系统属性中的内联 JSON )。

  11. 命令行参数,(例如,–server.port=9000, SpringApplication 会将任何命令行选项参数转换为 propert y并将其添加到 Spring 的 Environment 中。)

    • 如果你不希望命令行属性被添加到 Environment 中,你可以通过使用 SpringApplication.setAddCommandLineProperties(false) 来禁用它们。
  12. properties 属性在你的 tests 上。在 @SpringBootTest 和用于测试你的应用程序的特定片断的测试注释上可用。

  13. @TestPropertySource 对你的测试进行注解。

  14. 当 devtools 处于活动状态时,在 $HOME/.config/spring-boot 目录下的 Devtools 全局设置属性。

以上内容需要亲自使用测试,来掌握具体内容。

例如:

在你的应用程序的classpath(例如,在你的 jar 中),你可以有一个 application.properties 文件,为 name 提供一个合理的默认属性值。当在一个新的环境中运行时,可以在 jar 之外提供一个 application.properties 文件,覆盖 name 。

注:

envconfigprops端点在确定一个属性为什么有一个特定的值时很有用,具体可以参考 Production ready features 章节

个人理解:文档中的 优先(takes precedence),应该是使用的优先级,当存在a属性时,先使用a,当a不存在时,使用b。而属性加载的顺序更好相反,这样后面读取的才能更好地覆盖前面的读取的值。

问题:

  1. lower order property sources , 这里的 lower order 是在哪里定义的?
  2. The list is ordered by precedence (with values from lower items overriding earlier ones). 列表按优先级排序(较低项目的值覆盖较早项目的值)
    • 这里也是,这个 lower items 是怎么定义的? a,b,c 这三个值,a低?还是c低? 这是国外固有的顺序?还是哪里定义的顺序?
    • 从上下文来看,a>b>c,但是还是对官方文档中使用 lower 这个词有疑惑。

外部配置详细说明

2.1 访问命令行属性

2.2 JSON Application Properties

2.3 External Application Properties (外部 application.properties 属性配置文件)

2.3.1 加载使用 application.properties 配置文件

当你的应用程序启动时,Spring Boot 会自动从以下位置找到并加载 application.propertiesapplication.yaml 文件。

  1. classpath
    1. classpath的根路径
    2. classpath /config
  2. 当前目录
    1. 当前目录根路径
    2. 当前目录下的 /config 子目录
    3. /config 子目录的直接子目录。

      列表按优先级排序(在列表较低位置定义的属性会覆盖在较高位置定义的属性)。
      加载的文件被作为 PropertySources 添加到 Spring 的 Environment 中。

修改默认名字或者路径:

  • spring.config.name
  • spring.config.location
  • spring.config.extra-location (Spring Boot 2.5.3 版本使用)
    • spring.config.additional-location (Spring Boot 2.1.1-RELEASE 版本使用)

      通过将上述参数定义为环境属性(通常是 OS 环境变量(操作系统环境变量),系统属性或命令行参数)。

**spring.config.name**, 如果您不喜欢 application.properties 作为配置文件名,则可以通过指定 spring.config.name 环境属性来切换到另一个文件名。例如:改为 myproject.properties 和 myproject.yaml 文件

1
$ java -jar myproject.jar --spring.config.name=myproject

**spring.config.location**, 您还可以使用 spring.config.location 环境属性(这是目录位置或文件路径的逗号分隔列表)来引用显式位置。下面的示例演示如何指定其他文件名:

1
2
3
$ java -jar myproject.jar --spring.config.location=\
optional:classpath:/default.properties,\
optional:classpath:/override.properties

如果位置是可选的并且你不介意它们不存在,请使用前缀 optional:

注: 通过使用 spring.config.location 配置的位置将取代默认位置。如果你想添加额外的位置,而不是替换它们,你可以使用 spring.config.extra-location 。从附加位置加载的属性可以覆盖默认位置的属性。

具体样例参考官方文档:外部 application.properties

2.3.2 配置文件特定属性 (Profile Specific Files)

除了 application.properties 文件之外,Spring Boot 还将尝试使用命名惯例 application-{profile}加载特定配置文件(profile-specific files)。例如,如果你的应用程序激活了名为 prod 的配置文件并使用 YAML 文件,那么 application.ymlapplication-prod.yml 都将被考虑。

特定配置文件与标准的application.properties的位置相同,特定配置文件总是优先于非特定文件。如果指定了几个配置文件,则采用最后胜出的策略。例如,如果配置文件 prod,live 是由spring.profiles.active属性指定的,application-prod.properties中的值可以被application-live.properties中的值覆盖。

如何设置/激活,特定配置文件,结合

2.3.3 属性中的占位符(Property Placeholders)

application.propertiesapplication.yml中的值在使用时通过现有的 Environment 过滤,所以你可以参考以前定义的值(例如,从系统属性)。标准的 ${name} 属性占位符语法可以在一个值的任何地方使用。

例如,下面的文件将把app.description设置为 “MyApp is a Spring Boot application”。

1
2
3
4
app:
name: "MyApp"
description: "${app.name} is a Spring Boot application"

您还可以使用此技术来创建现有 Spring Boot 属性的“简短”变体。详细参考 How-to章节的使用短命令行参数章节

2.4 加密配置属性

2.5 使用YAML (使用 yaml 代替 properties 配置文件)

具体参考官方文档

YAML是 JSON 的超集,因此是一种用于指定层次结构配置数据的便捷格式。

  1. 使用条件,

    • 只要在 Classpath 上具有 SnakeYAML库,SpringApplication 类就会自动支持 YAML 作为属性的替代方法。

      如果您使用“Starter”,则 spring-boot-starter自动提供 SnakeYAML。

  2. 如何加载 YAML ?

  3. YAML 缺点

    • YAML文件不能通过使用 @PropertySource@TestPropertySource 注解来加载。所以,在你需要以这种方式加载值的情况下,你需要使用一个properties文件。

2.6 配置随机值 (Ramdom)

2.7 配置系统环境属性 (Configuring System Environment Properties)

2.8 类型安全的配置属性 ( Type-safe Configuration Properties)

该章节主要介绍 @ConfigurationProperties 注解相关内容,具体参考官方文档,Type-safe Configuration Properties

背景:

使用 @Value("${property}") 注解来注入配置属性有时会很麻烦,特别是当你要处理多个属性或你的数据是分层的。Spring Boot提供了一种处理属性的替代方法,让强类型的 Bean 管理和验证你的应用程序的配置。

Spring Boot提供了绑定 @ConfigurationProperties 类型并将其注册为Bean的基础设施。

另请参见 @Value和类型安全配置属性的区别

2.8.1 JavaBean 属性绑定

2.8.2 构造函数绑定

2.8.3 启用(Enabling) @ConfigurationProperties-annotated 类型

2.8.4 使用(Using) @ConfigurationProperties-annotated 类型

2.8.5 第三方配置

2.8.6 宽松绑定

2.8.7 合并复杂类型

2.8.8 属性转换

2.8.9 @ConfigurationProperties 验证

2.8.10 @ConfigurationProperties vs. @Value

@Value 注解是一个核心的容器功能,它不提供与 类型安全的配置属性(@ConfigurationProperties) 相同的功能。下表总结了 @ConfigurationProperties@Value 所支持的功能。

Feature @ConfigurationProperties @Value f
Relaxed binding Yes Limited (see note below)
Meta-data support Yes No
SpEL evaluation No Yes

3. Profiles

具体参考 官方文档

我个人理解,它的功能就是根据配置的参数,支持在不同的环境中使用参数指定的配置文件。

3.1 利用 @Profile 指定应用程序配置何时被加载

Spring Profiles提供了一种方法来隔离你的应用程序配置的一部分,使其只在某些环境下可用。任何 @Component@Configuration@ConfigurationProperties 都可以用 @Profile 来标记,以限制它何时被加载。

1
2
3
4
5
6
7
8
9
10
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {

// ...

}

如果 @ConfigurationProperties Bean 是通过 @EnableConfigurationProperties 注册的,而不是自动扫描,则需要在具有 @EnableConfigurationProperties 注解的 @Configuration 类上指定 @Profile 注解。在 @ConfigurationProperties 被扫描的情况下,@Profile 可以在 @ConfigurationProperties 类本身指定。

3.2 如何 启用/激活 不同的配置文件

使用 spring.profiles.active 这个Environment属性来指定哪些配置文件是活动的。可以将这个属性添加到配置文件中,同样也可以使用命令行参数的形式替换。例如:

1
spring.profiles.active=dev,hsqldb

或者使用命令行的形式:

1
--spring.profiles.active=dev,hsqldb

注:如果没有配置 active 状态的配置文件(profile),Spring 就会启用一个默认的配置文件,例如:application-default.properties
当然我们也可以通过 spring.profiles.default 这个 Environment 属性,来做调整, 例如: spring.profiles.default=none

spring.profiles.active 属性的生效覆盖方式,与其他普通属性一样,加载生效顺序,参考 外化配置

例如:可以在application.properties中指定活动配置文件,然后通过使用命令行开关替换它们。

有时,有一些属性可以添加到活动配置文件中,而不是替换它们。参见SpringApplication API中的setAdditionalProfiles()方法。

4. Logging

详细内容参考 官方文档logging

一般来说,你不需要改变你的日志依赖,Spring Boot的默认值就很好用。

如果你使用 “Starter”,Logback被用来做日志记录

4.1. 日志格式

日志级别: ERROR, WARN, INFO, DEBUG, 或TRACE.

Logback没有FATAL级别。它被映射到 ERROR。

4.3. 输出到文件

默认情况下,Spring Boot只向控制台记录日志,不写日志文件。

如果你想在控制台输出之外写日志文件,你需要设置 logging.file.namelogging.file.path 属性(例如,在你的 application.properties)。

下表显示了 logging.* 属性如何被一起使用。

logging.file.name logging.file.path Example Description
(none) (none) 只在控制台进行记录。
指定文件 (none) my.log 写到指定的日志文件。名称可以是准确的位置,也可以是与当前目录的相对位置。
(none) 指定目录 /var/log 将spring.log写到指定目录。名称可以是准确的位置,也可以是与当前目录的相对位置。

日志文件在达到 10MB 时就会轮换,与控制台输出一样,默认情况下会记录 ERROR-级、WARN-级和 INFO-级的信息。

其他的如,日志文件轮询策略等参考官方文档。

4.8. 自定义日志配置

根据你的日志系统,会加载以下文件。

Logging System Customization
Logback logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util Logging) logging.properties

7. 开发 Web Applications

大多数Web应用程序使用 spring-boot-starter-web 模块来快速启动和运行。

使用 spring-boot-starter-webflux 模块来构建 reactive Web 应用。

7.1. Spring Web MVC 框架

创建特殊的 @Controller@RestController bean 来处理 HTTP 请求。

控制器中的方法通过使用 @RequestMapping 注解被映射到 HTTP。

Spring MVC是Spring框架核心的一部分,详细的信息可以在 参考文档 中找到

7.1.1. Spring MVC自动配置

7.1.2. HttpMessageConverters

Spring MVC 使用 HttpMessageConverter 接口来转换 HTTP 请求和响应。

它支持一些开箱即用的默认值,
例如:

  1. 对象可以自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展,如果可用的话,或通过使用 JAXB,如果 Jackson XML扩展不可用)。

  2. 默认情况下,字符串是以 UTF-8 编码的。

你可以使用 Spring Boo t的 HttpMessageConverters 类,添加或定制转换器。

任何存在于上下文中的 HttpMessageConverter bean都会被添加到转换器的列表中。

7.1.3. 自定义 JSON Serializers 和 Deserializers

如果你使用 Jackson 来序列化和反序列化 JSON 数据,你可能想编写自己的 JsonSerializer 和 JsonDeserializer 类。

自定义序列化器通常是通过模块与Jackson注册,但 Spring Boot 提供了一个替代性的 @JsonComponent 注解,使直接注册 Spring Beans 更容易。

关于 @JsonComponent 注解使用场景

  1. 你可以直接在 JsonSerializerJsonDeserializerKeyDeserializer 实现上使用 @JsonComponent 注解。
  2. 也可以在那些包含序列化器/反序列化器作为内部类(inner classes)的类上使用它。
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
import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import org.springframework.boot.jackson.JsonComponent;

@JsonComponent
public class MyJsonComponent {

public static class Serializer extends JsonSerializer<MyObject> {

@Override
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
}

}

public static class Deserializer extends JsonDeserializer<MyObject> {

@Override
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectCodec codec = jsonParser.getCodec();
JsonNode tree = codec.readTree(jsonParser);
String name = tree.get("name").textValue();
int age = tree.get("age").intValue();
return new MyObject(name, age);
}

}

}

ApplicationContext 中的所有 @JsonComponent Bean 都会自动向 Jackson 注册。因为 @JsonComponent 是用 @Component 元注释的,所以通常的组件扫描规则适用。

Spring Boot还提供了 JsonObjectSerializerJsonObjectDeserializer 基类,在序列化对象时提供了标准 Jackson 版本的有用替代品。详情见 Javadoc 中的 JsonObjectSerializerJsonObjectDeserializer

7.1.5. 静态内容

默认情况下,Spring Boot从 classpath 中的 /static (或 /public/resources/META-INF/resources )目录或 ServletContext 的根中提供静态内容。它使用了 Spring MVC 中的 ResourceHttpRequestHandler ,因此你可以通过添加你自己的 WebMvcConfigurer 并重写 addResourceHandlers 方法来修改该行为。

具体参考官方文档

7.1.7. 路径匹配和内容协商

https://docs.spring.io/spring-boot/docs/2.5.3/reference/html/features.html#features.developing-web-applications.spring-mvc.content-negotiation

Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射(例如,控制器方法上的 @GetMapping 注解)相匹配,将传入的 HTTP 请求映射到处理程序。

Spring Boot 默认选择禁用后缀模式匹配,这被认为是一个 Spring MVC应用的最佳实践

这意味着诸如 "GET /projects/spring-boot.json" 之类的请求将不会与 @GetMapping("/projects/spring-boot") 映射相匹配。

  • 为什么?不用后缀模式匹配不是反而能匹配到吗?

背景:

过去,此功能主要用于未发送正确的“ Accept”请求 Headers 的 HTTP Client 端。我们需要确保将正确的 Content Type 发送给 Client 端。如今,内容协商(Content Negotiation)已变得更加可靠。

注: 后缀模式匹配已被废弃,并将在未来的版本中被删除。如果你了解这些注意事项,并且仍然希望你的应用程序使用后缀模式匹配,则需要进行以下配置。

1
2
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true

7.1.8. ConfigurableWebBindingInitializer

7.1.9. 模板引擎

作用:

  • 提供动态 HTML 内容

Spring Boot包括对以下模板引擎的自动配置支持。

当你使用这些默认配置的模板引擎之一时,你的模板会自动从 src/main/resources/templates 中获取。

模板引擎具体该怎么用,请参考各个模板引擎的官网

1
根据您运行应用程序的方式,IntelliJ IDEA 对 Classpath 的排序方式不同。与使用 Maven 或 Gradle 或从打包的 jar 运行应用程序时,从 IDE 的 Main 方法运行应用程序的顺序会有所不同。这可能会导致 Spring Boot 无法在 Classpath 上找到模板。如果遇到此问题,则可以在 IDE 中重新排序 Classpath,以首先放置模块的类和资源。另外,您可以配置模板前缀以搜索 Classpath 上的每个templates目录,如下所示:classpath*:/templates/。

7.1.12. 跨域支持 (CORS 支持)

Cross-origin resource sharing (CORS) 是一个由大多数浏览器实现的 W3C 规范,它让你以灵活的方式指定什么样的跨域请求是被授权的。而不是使用一些不太安全、不太强大的方法,如 IFRAME 或 JSONP。

从 4.2 版本开始,Spring MVC 支持 CORS。

7.2 Spring WebFlux框架

详细内容,参考官方文档 The “Spring WebFlux Framework”

Spring WebFlux 是 Spring Framework 5.0 中引入的新的响应式 Web 框架。

与 Spring MVC 不同,它不需要 Servlet API,是完全异步和非阻塞的,并通过 Reactor 项目实现了 Reactive Streams 规范。

在你的应用程序中同时添加 spring-boot-starter-webspring-boot-starter-webflux 模块,Spring Boot 会自动配置 Spring MVC,而不是 WebFlux。

7.4. 嵌入式 Servlet 容器支持

更多内容参考官方文档 Embedded Servlet Container Support

Spring Boot 包含对嵌入式 Tomcat,Jetty 和 Undertow 服务器的支持。

使用适当的 “Starter”来获得一个完全配置的实例。

默认情况下,嵌入式服务器在端口 8080 上监听 HTTP 请求。

7.5. 嵌入式Reactive务器支持

Spring Boot 对以下嵌入式反应式Web服务器的支持。

  • Reactor Netty
  • Tomcat
  • Jetty
  • Undertow

11. 使用SQL数据库

11.1. 配置数据源

详细内容,参考官方文档 Configure a DataSource

Data Access
2.1.1.RELEASE 有汉化版本

11.2. 使用JdbcTemplate

11.3. JPA 和 Spring Data JPA

11.4. Spring Data JDBC

11.5. 使用H2的Web Console

11.6. 使用 jOOQ

11.7. 使用 R2DBC

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信