1. Spring Boot
本节将详细介绍如何使用Spring Boot。它涵盖了诸如构建系统,自动配置以及如何运行应用程序之类的主题。 我们还将介绍一些Spring Boot最佳实践。尽管Spring Boot并没有什么特别的地方(它只是另一个可以使用的库), 但是有一些建议可以使你的开发过程更轻松一些。
1.1. 构建系统
强烈建议你选择一个支持依赖关系管理并且可以使用发布到“ Maven Central”存储库的工件的构建系统。 我们建议你选择Maven或Gradle。可以使Spring Boot与其他构建系统(例如,Ant)一起使用,但是它们并没有得到很好的支持。
1.1.1. 依赖管理
每个Spring Boot版本都提供了它所支持的依赖关系的精选列表。实际上,你不需要为构建配置中的所有这些依赖项提供版本, 因为Spring Boot会为你管理该版本。当你升级Spring Boot本身时,这些依赖项也会以一致的方式升级。
你仍然可以指定版本,并在需要时覆盖Spring Boot的建议版本。 |
精选列表包含可与Spring Boot一起使用的所有spring模块以及完善的第三方库列表。
该列表作为可与Maven和Gradle
一起使用的标准物料清单(spring-boot-dependencies
)提供。
Spring Boot的每个发行版都与Spring Framework的基本版本相关联。强烈 建议你不要更改其版本。 |
1.1.2. Maven
Maven用户可以从 spring-boot-starter-parent
项目继承来获得合理的默认值。父项目提供以下功能:
-
Java 1.8是默认的编译器级别。
-
UTF-8源编码。
-
从spring-boot-dependencies pom继承的依赖管理部分, 它管理公共依赖项的版本。当在自己的pom中使用这些依赖关系时,可以为这些依赖关系省略
<version>
标记。 -
使用
repackage
执行id执行repackage
目标。 -
明智的 资源过滤.
-
明智的插件配置 (exec plugin, Git commit ID 和 shade).
-
对
application.properties
和application.yml
进行明智的资源过滤,包括特定于环境的文件 (例如:application-dev.properties
和application-dev.yml
)
请注意,由于 application.properties
和 application.yml
文件接受Spring样式的占位符(${…}
),
因此Maven过滤已更改为使用 @..@
占位符。(你可以通过设置一个名为 resource.delimiter
的Maven属性来覆盖它。)
继承Starter Parent
要将项目配置为从 spring-boot-starter-parent
继承,请设置 parent
,如下所示:
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
你只需要为此依赖项指定Spring Boot版本号。如果导入其他starter,则可以安全地省略版本号。 |
使用该设置,你还可以通过覆盖自己项目中的属性来覆盖各个依赖项。例如,要升级到另一个Spring Data发布系列,
可以将以下内容添加到 pom.xml
中:
<properties>
<spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
</properties>
检查 spring-boot-dependencies pom以获取受支持属性的列表。
|
在没有父POM的情况下使用Spring Boot
并非每个人都喜欢从 spring-boot-starter-parent
父POM继承。你可能需要使用自己公司的标准父POM,或者可能希望显式声明所有Maven配置。
如果你不想使用 spring-boot-starter-parent
,仍然可以通过使用 scope=import
依赖项来保留依赖项管理(而不是插件管理)的好处,如下所示:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
如上所述,前面的示例设置不允许你使用属性来覆盖各个依赖项。为了获得相同的结果,
需要在项目的 dependencyManagement
中 spring-boot-dependencies
条目 之前 添加一个条目。
例如,要升级到另一个Spring Data发布系列,可以将以下元素添加到 pom.xml
中:
<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.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在前面的示例中,我们指定了 BOM,但是可以以相同方式覆盖任何依赖项类型。 |
使用Spring Boot Maven插件
Spring Boot包含一个 Maven插件,
可以将项目打包为可执行jar。如果要使用插件,请将其添加到你的 <plugins>
部分,如以下示例所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果你使用Spring Boot starter parent pom,则只需添加插件。除非你要更改父级中定义的设置,否则无需对其进行配置。 |
1.1.4. Ant
可以使用Apache Ant+Ivy构建Spring Boot项目。spring-boot-antlib
“AntLib
”模块也可用于帮助Ant创建可执行jar。
为了声明依赖关系,典型的 ivy.xml
文件看起来类似于以下示例:
<ivy-module version="2.0">
<info organisation="org.springframework.boot" module="spring-boot-sample-ant" />
<configurations>
<conf name="compile" description="everything needed to compile this module" />
<conf name="runtime" extends="compile" description="everything needed to run this module" />
</configurations>
<dependencies>
<dependency org="org.springframework.boot" name="spring-boot-starter"
rev="${spring-boot.version}" conf="compile" />
</dependencies>
</ivy-module>
典型的 build.xml
类似于以下示例:
<project
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
<property name="spring-boot.version" value="2.2.2.RELEASE" />
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]" />
</target>
<target name="classpaths" depends="resolve">
<path id="compile.classpath">
<fileset dir="lib/compile" includes="*.jar" />
</path>
</target>
<target name="init" depends="classpaths">
<mkdir dir="build/classes" />
</target>
<target name="compile" depends="init" description="compile">
<javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath" />
</target>
<target name="build" depends="compile">
<spring-boot:exejar destfile="build/myapp.jar" classes="build/classes">
<spring-boot:lib>
<fileset dir="lib/runtime" />
</spring-boot:lib>
</spring-boot:exejar>
</target>
</project>
如果你不想使用 spring-boot-antlib
模块,请参阅 不使用spring-boot-antlib “How-to
”从Ant构建可执行存档。
1.1.5. Starters
启动器是一组便捷的依赖项描述符,你可以在应用程序中包括它们。你可以一站式安装所需的所有Spring和相关技术,
而不必遍历示例代码和依赖描述符复制粘贴它。例如,如果要开始使用Spring和JPA进行数据库访问,请在项目中包括 spring-boot-starter-data-jpa
依赖项。
启动器包含许多启动项目并快速运行所需的依赖项,并且具有一组受支持的被管理的传递性依赖项。
Spring Boot在 org.springframework.boot
组下提供了以下应用程序启动器:
名称 | 描述 | Pom |
---|---|---|
|
核心启动器,包括自动配置支持,日志记录和YAML |
|
|
使用Apache ActiveMQ的JMS消息传递启动器 |
|
|
使用Spring AMQP和Rabbit MQ的启动器 |
|
|
使用Spring AOP和AspectJ进行面向方面编程的启动器 |
|
|
使用Apache Artemis的JMS消息传递启动器 |
|
|
使用Spring Batch的启动器 |
|
|
使用Spring Framework缓存支持的启动器 |
|
|
使用Spring Cloud Connectors的启动器,可简化与Cloud Foundry和Heroku等云平台中服务的连接。不赞成使用Java CFEnv |
|
|
使用Cassandra分布式数据库和Spring Data Cassandra的启动器 |
|
|
使用Cassandra分布式数据库和Spring Data Cassandra Reactive的启动器 |
|
|
使用Couchbase面向文档的数据库和Spring Data Couchbase的启动器 |
|
|
使用Couchbase面向文档的数据库和Spring Data Couchbase Reactive的启动器 |
|
|
使用Elasticsearch搜索和分析引擎以及Spring Data Elasticsearch的启动器 |
|
|
使用Spring Data JDBC的启动器 |
|
将Spring Data JPA与Hibernate结合使用的启动器 |
||
|
使用Spring Data LDAP的启动器 |
|
|
使用MongoDB面向文档的数据库和Spring Data MongoDB的启动器 |
|
|
使用MongoDB面向文档的数据库和Spring Data MongoDB Reactive的启动器 |
|
|
使用Neo4j图数据库和Spring Data Neo4j的启动器 |
|
|
将Redis键值对数据库与Spring Data Redis和Lettuce客户端一起使用的启动器 |
|
|
将Redis键值对数据库与Spring Data Redis Reacting和Lettuce客户端一起使用的启动器 |
|
|
使用Spring Data REST在REST上公开Spring Data存储库的启动器 |
|
|
使用Apache Solr搜索平台和Spring Data Solr的启动器 |
|
|
使用FreeMarker视图构建MVC Web应用程序的启动器 |
|
|
使用Groovy模板视图构建MVC Web应用程序的启动器 |
|
|
使用Spring MVC和Spring HATEOAS构建基于超媒体的RESTful Web应用程序的启动器 |
|
|
使用Spring Integration的启动器 |
|
通过HikariCP连接池使用JDBC的启动器 |
||
|
使用JAX-RS和Jersey构建RESTful Web应用程序的启动器。
|
|
|
使用jOOQ访问SQL数据库的启动器。
|
|
|
读写JSON的启动器 |
|
|
使用Atomikos的JTA事务启动器 |
|
|
使用Bitronix的JTA事务启动器 |
|
|
使用Java Mail和Spring Framework的电子邮件发送支持的启动器 |
|
|
使用Mustache视图构建Web应用程序的启动器 |
|
|
使用Spring Security的OAuth2/OpenID Connect客户端功能的启动器 |
|
|
使用Spring Security的OAuth2资源服务器功能的启动器 |
|
|
使用Quartz Scheduler的启动器 |
|
|
用于构建RSocket客户端和服务器的启动器 |
|
|
使用Spring Security的启动器 |
|
|
使用包括JUnit,Hamcrest和Mockito在内的库测试Spring Boot应用程序的启动器 |
|
|
使用Thymeleaf视图构建MVC Web应用程序的启动器 |
|
|
通过Hibernate Validator使用Java Bean验证的启动器 |
|
使用Spring MVC构建Web(包括RESTful)应用程序的启动器。使用Tomcat作为默认的嵌入式容器 |
||
|
使用Spring Web Services的启动器 |
|
|
使用Spring Framework的响应式Web支持构建WebFlux应用程序的启动器 |
|
|
使用Spring Framework的WebSocket支持构建WebSocket应用程序的启动器 |
除了应用程序启动程序,以下启动程序可用于添加 生产就绪 功能:
名称 | 描述 | Pom |
---|---|---|
|
使用Spring Boot的Actuator的启动器,它提供了生产就绪功能,可帮助您监视和管理应用程序 |
最后,Spring Boot还包括以下启动程序,如果你想排除或替换特定的技术方面,可以使用这些启动程序:
名称 | 描述 | Pom |
---|---|---|
|
使用Jetty作为嵌入式servlet容器的启动器。 |
|
|
使用Log4j2进行日志记录的启动器。 |
|
使用Logback进行日志记录的启动器。默认日志记录启动器 |
||
|
使用Reactor Netty作为嵌入式响应式HTTP服务器的启动器 |
|
用于将Tomcat用作嵌入式servlet容器的启动器。 |
||
|
使用Undertow作为嵌入式servlet容器的启动器。 |
有关社区贡献的其他启动程序的列表,请参阅GitHub上 spring-boot-starters 模块中的
README文件。
|
1.2. 结构化你的代码
Spring Boot不需要任何特定的代码布局即可工作。但是,有一些最佳做法对你会有所帮助。
1.2.1. 使用“default
”包
当类不包含 package
声明时,将其视为在“default package
”中。通常不建议使用“default package
”,应避免使用。
对于使用 @ComponentScan
,@ConfigurationPropertiesScan
,@EntityScan
或 @SpringBootApplication
注解的Spring Boot应用程序,这可能会引起特定的问题,因为每个jar中的每个类都会被读取。
我们建议你遵循Java建议的程序包命名约定,并使用反向域名(例如:com.example.project )。
|
1.2.2. 找到应用程序主类
我们通常建议你将应用程序主类放在其他类之上的根包中。@SpringBootApplication
注解通常放在你的主类上,它隐式定义某些条目的基本“search package
”。
例如,如果你正在编写JPA应用程序,则使用带 @SpringBootApplication
注解的类的包来搜索 @Entity
条目。
使用根软件包还允许组件扫描仅应用于你的项目。
如果你不想使用 @SpringBootApplication ,则可以通过导入的
@EnableAutoConfiguration 和 @ComponentScan 注解来定义该行为,因此也可以使用它们。
|
以下清单显示了典型的布局:
com +- example +- myapplication +- Application.java | +- customer | +- Customer.java | +- CustomerController.java | +- CustomerService.java | +- CustomerRepository.java | +- order +- Order.java +- OrderController.java +- OrderService.java +- OrderRepository.java
Application.java
文件将声明 main
方法以及基本的 @SpringBootApplication
注解,如下所示:
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1.3. 配置类
Spring Boot支持基于Java的配置。尽管可以将 SpringApplication
与XML源一起使用,但是我们通常建议你的主要源为单个
@Configuration
类。通常,定义 main
方法的类是首选的 @Configuration
。
在互联网上已经发布了许多使用XML配置的Spring配置示例。如果可能,请始终尝试使用等效的基于Java的配置。
搜索 Enable* 注解可能是一个不错的起点。
|
1.3.1. 导入其他配置类
你无需将所有 @Configuration
放在单个类中。@Import
注解可用于导入其他配置类。
另外,你可以使用 @ComponentScan
自动拾取所有Spring组件,包括 @Configuration
类。
1.3.2. 导入XML配置
如果绝对必须使用基于XML的配置,我们建议你仍然从 @Configuration
类开始。然后使用 @ImportResource
注解来加载XML配置文件。
1.4. 自动配置
Spring Boot自动配置会尝试根据添加的jar依赖项自动配置Spring应用程序。例如,如果 HSQLDB
在类路径上,
并且你尚未手动配置任何数据库连接bean,则Spring Boot会自动配置内存数据库。
你需要通过将 @EnableAutoConfiguration
或 @SpringBootApplication
注解添加到你的 @Configuration
类之一来启用自动配置。
你应该只添加一个 @SpringBootApplication 或 @EnableAutoConfiguration 注解。
我们通常建议你仅将它们中的一个添加到你的主要 @Configuration 类中。
|
1.4.1. 逐渐取代自动配置
自动配置是非侵入性的。在任何时候,你都可以开始定义自己的配置,以替换自动配置的特定部分。
例如,如果你添加自己的 DataSource
bean,则默认的嵌入式数据库支持将回退。
如果你需要了解当前正在应用哪些自动配置以及原因,请使用 --debug
开关启动你的应用程序。
这样做可以启用调试日志以供选择核心记录器,并将条件报告记录到控制台。
1.4.2. 禁用特定的自动配置类
如果发现正在应用某个不需要的特定自动配置类,则可以使用 @EnableAutoConfiguration
的 exclude
属性禁用它们,如以下示例所示:
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
如果该类不在类路径中,则可以使用注解的 excludeName
属性,并指定完全限定的名称。最后,你还可以使用
spring.autoconfigure.exclude
属性控制要排除的自动配置类的列表。
你可以在注解级别和使用属性来定义排除项。 |
即使自动配置类是 public ,类中唯一被认为是公共API的是类的名称,它可以用来禁用自动配置。
这些类的实际内容(例如:嵌套配置类或Bean方法)仅供内部使用,我们不建议直接使用它们。
|
1.5. Spring Beans和依赖注入
你可以自由使用任何标准的Spring Framework技术来定义bean及其注入依赖关系。为简单起见,我们经常发现使用
@ComponentScan
(查找你的bean)和使用 @Autowired
(进行构造函数注入)效果很好。
如果按照上面的建议构造代码(将应用程序类放在根包中),则可以添加 @ComponentScan
,而无需添加任何参数。
你的所有应用程序组件(@Component
,@Service
,@Repository
,@Controller
等)都将自动注册为Spring Bean。
以下示例显示了一个 @Service
Bean,它使用构造函数注入来获取所需的 RiskAssessor
Bean:
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
@Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
如果bean具有一个构造函数,则可以省略 @Autowired
,如以下示例所示:
@Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
请注意如何使用构造函数注入将 riskAssessor 字段标记为 final ,以表示它随后不能更改。
|
1.6. 使用@SpringBootApplication注解
许多Spring Boot开发人员喜欢他们的应用程序使用自动配置,组件扫描,并能够在其“应用程序类”上定义额外的配置。
单个 @SpringBootApplication
注解可用于同时启用这三个功能,即:
-
@EnableAutoConfiguration
: 启用Spring Boot的自动配置机制 -
在应用程序所在的软件包上启用
@Component
扫描(请参阅最佳实践) -
@Configuration
: 允许在上下文中注册额外的bean或导入其他配置类
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication 还提供别名以自定义 @EnableAutoConfiguration 和 @ComponentScan 的属性。
|
这些功能都不是强制性的,你可以选择用它启用的任何功能替换这个单个注解。例如,你可能不想在应用程序中使用组件扫描或配置属性扫描:
在此示例中,除了没有自动检测到 |
1.7. 运行你的应用程序
将应用程序打包为jar并使用嵌入式HTTP服务器的最大优势之一是,你可以像运行其他应用程序一样运行应用程序。 调试Spring Boot应用程序也很容易。你不需要任何特殊的IDE插件或扩展。
本节仅介绍基于jar的包装。如果选择将应用程序打包为war文件,则应参考服务器和IDE文档。 |
1.7.1. 从IDE运行
你可以将IDE中的Spring Boot应用程序作为简单的Java应用程序运行。但是,你首先需要导入你的项目。
导入步骤因你的IDE和构建系统而异。大多数IDE可以直接导入Maven项目。例如:Eclipse用户可以从 File
中选择 Import…
→ Existing Maven Projects
。
如果不小心两次运行Web应用程序,则会看到“Port already in use ”错误。
STS用户可以使用 Relaunch 按钮而不是 Run 按钮来确保关闭任何现有实例。
|
1.7.2. 作为打包的应用程序运行
如果使用Spring Boot Maven或Gradle插件创建可执行jar,则可以使用 java -jar
运行应用程序,如以下示例所示:
$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
也可以在启用了远程调试支持的情况下运行打包的应用程序。这样做使你可以将调试器附加到打包的应用程序,如以下示例所示:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \ -jar target/myapplication-0.0.1-SNAPSHOT.jar
1.7.3. 使用Maven插件
Spring Boot Maven插件包含一个 run
目标,可用于快速编译和运行你的应用程序。应用程序以爆炸形式运行,就像在IDE中一样。
以下示例显示了运行Spring Boot应用程序的典型Maven命令:
$ mvn spring-boot:run
你可能还想使用 MAVEN_OPTS
操作系统环境变量,如以下示例所示:
$ export MAVEN_OPTS=-Xmx1024m
1.7.4. 使用Gradle插件
Spring Boot Gradle插件包含一个 bootRun
任务,该任务可用于以爆炸形式运行你的应用程序。每当你应用
org.springframework.boot
和 java
插件时,都会添加 bootRun
任务,在以下示例中显示:
$ gradle bootRun
你可能还想使用 JAVA_OPTS
操作系统环境变量,如以下示例所示:
$ export JAVA_OPTS=-Xmx1024m
1.7.5. 热交换
由于Spring Boot应用程序只是普通的Java应用程序,因此JVM热交换应该可以立即使用。 JVM热交换在一定程度上受到它可以替换的字节码的限制。对于更完整的解决方案,可以使用 JRebel。
spring-boot-devtools
模块还包括对应用程序快速重启的支持。有关详细信息,请参见本章后面的开发者工具部分和
“How-to” 热交换。
1.8. 开发者工具
Spring Boot包含一组额外的工具,这些工具可以使应用程序开发体验更加愉快。
spring-boot-devtools
模块可以包含在任何项目中,以提供其他开发时功能。要包括devtools支持,
请将模块依赖项添加到你的构建中,如以下Maven和Gradle清单所示:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
运行完全打包的应用程序时,将自动禁用开发者工具。如果你的应用程序是以 java -jar 启动的,
或者是从特殊的类加载器启动的,则将其视为“生产应用程序 ”。如果这不适用于你(即如果你从容器中运行应用程序),
请考虑排除devtools或设置 -Dspring.devtools.restart.enabled=false 系统属性。
|
在Maven中将依赖项标记为optional或在Gradle中使用自定义 developmentOnly 配置(如上所示)是一种最佳实践,
它可以防止将devtools过渡地应用到使用你项目的其他模块。
|
重新打包的存档默认情况下不包含devtools。如果要使用某个远程devtools功能,
则需要禁用 excludeDevtools 构建属性以包括它。Maven和Gradle插件均支持该属性。
|
1.8.1. 属性默认值
Spring Boot支持的一些库使用缓存来提高性能。例如:模板引擎缓存已编译的模板,以避免重复解析模板文件。 另外,Spring MVC可以在提供静态资源时向响应添加HTTP缓存头。
尽管缓存在生产中非常有益,但在开发过程中可能适得其反,从而使你无法看到刚刚在应用程序中所做的更改。因此,默认情况下,spring-boot-devtools
禁用缓存选项。
缓存选项通常由 application.properties
文件中的设置配置。例如,Thymeleaf提供 spring.thymeleaf.cache
属性。
spring-boot-devtools
模块不需要手动设置这些属性,而是自动应用合理的开发时配置。
由于在开发Spring MVC和Spring WebFlux应用程序时需要有关Web请求的更多信息,因此开发者工具将为 web
日志记录组启用 DEBUG
日志记录。
这将为你提供有关传入请求,正在处理的处理程序,响应结果等的信息。如果你希望记录所有请求详细信息(包括潜在的敏感信息),
则可以打开 spring.http.log-request-details
配置属性。
如果你不希望应用默认属性,则可以在 application.properties 中将 spring.devtools.add-properties 设置为 false 。
|
有关devtools应用的属性完整列表,请参见 DevToolsPropertyDefaultsPostProcessor。 |
1.8.2. 自动重启
每当classpath上的文件更改时,使用 spring-boot-devtools
的应用程序都会自动重新启动。在IDE中工作时,
这可能是一个有用的功能,因为它为代码更改提供了非常快速的反馈循环。默认情况下,
将监视类路径上指向文件夹的任何条目的更改。请注意,某些资源(例如静态资产和视图模板)
不需要重新启动应用程序。
只要启用了forking,你还可以使用受支持的构建插件(Maven和Gradle)启动应用程序, 因为DevTools需要一个隔离的应用程序类加载器才能正常运行。默认情况下,Gradle和Maven插件会fork应用程序进程。 |
与LiveReload一起使用时,自动重启非常有效。有关详细信息,请参见LiveReload部分。 如果使用JRebel,则禁用自动重新启动,而支持动态类重新加载。其他devtools功能(例如LiveReload和属性覆盖)仍可以使用。 |
DevTools依赖于应用程序上下文的关闭钩子在重新启动期间将其关闭。如果你禁用了关闭钩子
(SpringApplication.setRegisterShutdownHook(false) ),它将无法正常工作。
|
在确定类路径上的条目是否应在更改后触发重新启动时,DevTools会自动忽略名为 spring-boot ,
spring-boot-devtools ,spring-boot-autoconfigure ,spring-boot-actuator 和 spring-boot-starter 的项目。
|
DevTools需要自定义 ApplicationContext 使用的 ResourceLoader 。如果你的应用程序已经提供了,它将被包装。
不支持在 ApplicationContext 上直接重写 getResource 方法。
|
记录条件评估中的更改
默认情况下,每次应用程序重新启动时,都会记录一个报告,其中显示了条件评估增量变化。 该报告显示了你进行代码更改(例如:添加或删除Bean以及设置配置属性)时所造成的对应用程序自动配置的更改。
要禁用报告的日志记录,请设置以下属性:
spring.devtools.restart.log-condition-evaluation-delta=false
排除资源
某些资源在更改时不一定需要触发重新启动。例如,Thymeleaf模板可以就地编辑。默认情况下,
更改 /META-INF/maven
,/META-INF/resources
,/resources
,/static
,/public
或 /templates
中的资源不会触发重新启动,但会触发实时重新加载。如果要自定义这些排除项,则可以使用
spring.devtools.restart.exclude
属性。例如:仅排除 /static
和 /public
,可以设置以下属性:
spring.devtools.restart.exclude=static/**,public/**
如果要保留这些默认值并 添加 其他排除项,请改用 spring.devtools.restart.additional-exclude 属性。
|
监视其他路径
禁用重启
如果你不想使用重新启动功能,则可以使用 spring.devtools.restart.enabled
属性将其禁用。在大多数情况下,你可以在
application.properties
中设置此属性(这样做仍会初始化重启类加载器,但它不会监视文件更改)。
如果你需要 完全 禁用重启支持(例如:因为它不适用于特定的库),则需要在调用 SpringApplication.run(…)
之前将
spring.devtools.restart.enabled
系统属性设置为 false
。如以下示例所示:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
使用触发文件
如果使用持续编译更改文件的IDE,则可能更喜欢仅在特定时间触发重新启动。为此,你可以使用“触发文件
”,
这是一个特殊文件,当你要实际触发重新启动检查时必须对其进行修改。
对文件的任何更新都将触发检查,但是只有在Devtools检测到有事情要做的情况下,重启才真正发生。 |
要使用触发文件,请将 spring.devtools.restart.trigger-file
属性设置为触发文件的名称(不包括任何路径)。
触发文件必须出现在类路径上的某个位置。
例如,如果你的项目具有以下结构:
src +- main +- resources +- .reloadtrigger
然后,你的 trigger-file
属性将是:
spring.devtools.restart.trigger-file=.reloadtrigger
现在仅在更新 src/main/resources/.reloadtrigger
时才可能发生重启。
你可能需要将 spring.devtools.restart.trigger-file 设置为全局设置,以便所有项目的行为均相同。
|
某些IDE具有使你不必手动更新触发器文件的功能。 Spring Tools for Eclipse和
IntelliJ IDEA (最终版)都具有这种支持。
使用Spring Tools,你可以从控制台视图使用“reload
”按钮(只要你的 trigger-file
为 .reloadtrigger
)。
对于IntelliJ,你可以按照
其文档中的说明进行操作。
自定义重启类加载器
如前面的重新启动 vs 重新加载部分所述,重新启动功能是通过使用两个类加载器实现的。 对于大多数应用程序,此方法效果很好。但是,有时可能会导致类加载问题。
默认情况下,IDE中的任何打开的项目都使用“重启
”类加载器加载,而任何常规的 .jar
文件都使用“基本
”类加载器加载。
如果你在多模块项目上工作,并且并非每个模块都导入到IDE中,则可能需要自定义内容。为此,你可以创建一个
META-INF/spring-devtools.properties
文件。
spring-devtools.properties
文件可以包含带有 restart.exclude
和 restart.include
前缀的属性。
include
元素是应上拉到“重启
”类加载器中的项目,而 exclude
元素是应下推到“基本
”类加载器中的项目。
该属性的值是应用于类路径的正则表达式模式,如以下示例所示:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\.]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\.]+\.jar
所有属性键都必须是唯一的。只要属性以 restart.include 或 restart.exclude 开头,它就会被考虑。
|
将加载类路径中的所有 META-INF/spring-devtools.properties 。你可以将文件打包到项目内部,也可以打包到项目使用的库中。
|
已知局限性
重新启动功能不适用于使用标准 ObjectInputStream
反序列化的对象。如果你需要反序列化数据,
则可能需要将Spring的 ConfigurableObjectInputStream
与 Thread.currentThread().getContextClassLoader()
结合使用。
不幸的是,一些第三方库在不考虑上下文类加载器的情况下反序列化。如果发现这样的问题,则需要向库的原始作者请求修复。
1.8.3. LiveReload
spring-boot-devtools
模块包括一个嵌入式LiveReload服务器,该服务器可用于在更改资源时触发浏览器刷新。
可从 livereload.com免费获得适用于Chrome,Firefox和Safari的LiveReload浏览器扩展。
如果你不想在应用程序运行时启动LiveReload服务器,则可以将 spring.devtools.livereload.enabled
属性设置为 false
。
一次只能运行一台LiveReload服务器。在启动应用程序之前,请确保没有其他LiveReload服务器正在运行。 如果从IDE启动多个应用程序,则只有第一个具有LiveReload支持。 |
1.8.4. 全局设置
你可以通过将以下任何文件添加到 $HOME/.config/spring-boot
文件夹来配置全局devtools设置:
-
spring-boot-devtools.properties
-
spring-boot-devtools.yaml
-
spring-boot-devtools.yml
添加到这些文件的任何属性都将应用于使用devtools的 所有 Spring Boot应用程序。例如:要将重新启动配置为始终使用 触发文件,应添加以下属性:
spring.devtools.restart.trigger-file=.reloadtrigger
如果在 $HOME/.config/spring-boot 中找不到devtools配置文件,则在 $HOME 文件夹的根目录中搜索是否存在
.spring-boot-devtools.properties 文件。这使你可以与不支持 $HOME/.config/spring-boot
位置的较旧版本的Spring Boot上的应用程序共享devtools全局配置。
|
上述文件中激活的Profiles不会影响 特定于环境的配置文件的加载。 |
1.8.5. 远程应用
Spring Boot开发者工具不仅限于本地开发。远程运行应用程序时,你还可以使用多种功能。 选择启用远程支持,因为启用它可能会带来安全风险。仅当在受信任的网络上运行或使用SSL保护时,才应启用它。 如果这两个选项都不可用,则不应使用DevTools的远程支持。你永远不要在生产部署上启用支持。
要启用它,你需要确保在重新打包的档案中包含 devtools
,如以下清单所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
然后,你需要设置 spring.devtools.remote.secret
属性。像任何重要的密码或机密一样,该值应唯一且强壮,以免被猜测或强行使用。
远程devtools支持分为两部分:接受连接的服务器端端点和在IDE中运行的客户端应用程序。设置
spring.devtools.remote.secret
属性后,将自动启用服务器组件,客户端组件必须手动启动。
运行远程客户端应用程序
远程客户端应用程序旨在在你的IDE中运行。你需要使用与你连接到的远程项目相同的类路径来运行
org.springframework.boot.devtools.RemoteSpringApplication
。该应用程序的唯一必需参数是它连接到的远程URL。
例如,如果你使用的是Eclipse或STS,并且有一个名为 my-app
的项目已部署到Cloud Foundry,则可以执行以下操作:
-
从
Run
菜单中选择Run Configurations…
。 -
创建一个新的
Java Application
“启动配置”。 -
浏览
my-app
项目。 -
使用
org.springframework.boot.devtools.RemoteSpringApplication
作为主类。 -
将
https://myapp.cfapps.io
添加到Program arguments
(或任何远程URL)。
正在运行的远程客户端可能类似于以下清单:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \ \\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) ) ' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / / =========|_|==============|___/===================================/_/_/_/ :: Spring Boot Remote :: 2.2.2.RELEASE 2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code) 2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy 2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'. 2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
因为远程客户端使用与真实应用程序相同的类路径,所以它可以直接读取应用程序属性。这就是读取 spring.devtools.remote.secret 属性并将其传递给服务器进行身份验证的方式。
|
始终建议使用 https:// 作为连接协议,以便对通信进行加密并且不能截获密码。
|
如果需要使用代理来访问远程应用程序,请配置 spring.devtools.remote.proxy.host 和 spring.devtools.remote.proxy.port 属性。
|
远程更新
远程客户端以与本地重新启动相同的方式监视应用程序类路径中的更改。 任何更新的资源都会推送到远程应用程序,并且(如果需要)会触发重新启动。 如果你迭代使用本地没有的云服务的功能,这将很有帮助。通常,远程更新和重新启动比完整的重新构建和部署周期快得多。
仅在远程客户端正在运行时监视文件。如果在启动远程客户端之前更改文件,则不会将其推送到远程服务器。 |
配置文件系统观察器
FileSystemWatcher 的工作方式是按一定的时间间隔轮询类更改,然后等待预定义的静默期以确保没有更多更改。 然后将更改上传到远程应用程序。在较慢的开发环境中,可能会发生静默期不够的情况,并且类中的更改可能会分为几批。 第一批类更改上传后,服务器将重新启动。由于服务器正在重新启动,因此下一批不能发送到应用程序。
这通常通过 RemoteSpringApplication
日志中的警告来证明,即有关上载某些类失败的消息,然后进行重试。
但是,这也可能导致应用程序代码不一致,并且在上传第一批更改后无法重新启动。
如果你经常观察到此类问题,请尝试将 spring.devtools.restart.poll-interval
和
spring.devtools.restart.quiet-period
参数增加到适合你的开发环境的值:
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
现在每2秒轮询一次受监视的classpath文件夹以进行更改,并保持1秒钟的静默时间以确保没有其他类更改。
1.9. 打包你的应用程序用于生产
可执行jar可以用于生产部署。由于它们是独立的,因此它们也非常适合云部署。
对于其他“生产就绪”功能,例如运行状况,审核和度量REST或JMX端点,请考虑添加 spring-boot-actuator
。
有关详细信息,请参见 生产就绪。
1.10. 接下来要读什么
现在,你应该了解了如何使用Spring Boot以及应遵循的一些最佳实践。现在,你可以继续深入了解特定的 Spring Boot功能,或者可以跳过并阅读有关 Spring Boot的 生产就绪 方面的信息。
2. Spring Boot特性
本节将深入介绍Spring Boot。在这里,你可以了解可能要使用和自定义的关键功能。开始之前,建议你先阅读Spring Boot部分, 以便你有足够的基础知识。
2.1. SpringApplication
SpringApplication
类提供了一种便捷的方式来引导从 main()
方法启动的Spring应用程序。在大多数情况下,
你可以委托给静态 SpringApplication.run
方法,如以下示例所示:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当你的应用程序启动时,你应该看到类似于以下输出的内容:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: v2.2.2.RELEASE 2019-04-31 13:09:54.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb) 2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy 2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080 2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)
默认情况下,显示 INFO
日志消息,包括一些相关的启动详细信息,例如:启动应用程序的用户。如果你需要除 INFO
级别以外的其他日志,
则可以按照日志级别中的说明进行设置。使用主应用程序类包中的实现版本来确定应用程序版本。
可以通过将 spring.main.log-startup-info
设置为 false
来关闭启动信息记录。这还将关闭对应用程序激活的环境配置文件的日志记录。
要在启动期间添加其他日志记录,可以在 SpringApplication 的子类中重写 logStartupInfo(boolean) 。
|
2.1.1. 启动失败
如果你的应用程序无法启动,则已注册的 FailureAnalyzers
将有机会提供专门的错误消息和解决该问题的具体措施。
例如:如果你在端口8080上启动Web应用程序并且该端口已在使用中,则应该看到类似于以下消息的内容:
*************************** APPLICATION FAILED TO START *************************** Description: Embedded servlet container failed to start. Port 8080 was already in use. Action: Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Spring Boot提供了大量的 FailureAnalyzer 实现,你可以添加自己的实现。
|
如果没有故障分析器能够处理该异常,你仍然可以显示完整条件报告以更好地了解出了什么问题。
为此,你需要为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用 debug
属性或
启用 DEBUG
日志记录。
例如,如果使用 java -jar
运行应用程序,则可以按以下方式启用 debug
属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
2.1.2. 延迟初始化
SpringApplication
允许延迟初始化应用程序。启用延迟初始化后,将根据需要创建bean,而不是在应用程序启动期间创建bean。
因此,启用延迟初始化可以减少应用程序启动所需的时间。在Web应用程序中,启用延迟初始化将导致许多与Web相关的Bean直到收到HTTP请求后才被初始化。
延迟初始化的缺点是,它可能会延迟发现应用程序问题的时间。如果错误配置的Bean被延迟初始化,则启动期间将不再发生故障, 并且只有在初始化Bean时问题才会发现。还必须注意确保JVM有足够的内存来容纳所有应用程序的bean, 而不仅仅是启动期间初始化的bean。由于这些原因,默认情况下不会启用延迟初始化, 因此建议在启用延迟初始化之前先对JVM的堆大小进行微调。
可以使用 SpringApplicationBuilder
上的 lazyInitialization
方法或 SpringApplication
上的
setLazyInitialization
方法以编程方式启用延迟初始化。另外,可以使用 spring.main.lazy-initialization
属性启用它,如以下示例所示:
spring.main.lazy-initialization=true
如果要在对应用程序其余部分使用延迟初始化时禁用某些bean的延迟初始化,则可以使用 @Lazy(false)
注解将它们的延迟属性显式设置为 false 。
|
2.1.3. 自定义横幅
可以通过将 banner.txt
文件添加到类路径或将 spring.banner.location
属性设置为此类文件的位置来更改启动时打印的横幅。
如果文件的编码不是UTF-8,则可以设置 spring.banner.charset
。除了文本文件之外,你还可以将
banner.gif
,banner.jpg
或 banner.png
图像文件添加到类路径中,或设置 spring.banner.image.location
属性。
图像将转换为ASCII艺术品并打印在任何文字横幅上方。
在 banner.txt
文件中,你可以使用以下任意占位符:
Variable | Description |
---|---|
|
你的应用程序的版本号,在 |
|
你在 |
|
你正在使用的Spring Boot版本。例如 |
|
你正在使用的Spring Boot版本的格式化显示(用小括号括起来并以v开头)。例如: |
|
其中 |
|
你在 |
如果你要以编程方式生成横幅,则可以使用 SpringApplication.setBanner(…) 方法。
使用 org.springframework.boot.Banner 接口并实现自己的 printBanner() 方法。
|
你还可以使用 spring.main.banner-mode
属性来确定横幅是否必须在 System.out
(控制台
)上打印,
是否必须发送到配置的日志记录器(log
)或根本不打印(关闭
)。
打印的横幅用 springBootBanner
名称注册为单例bean。
2.1.4. 自定义SpringApplication
如果 SpringApplication
的默认设置不符合你的喜好,你可以创建一个本地实例并对其进行自定义。例如:要关闭横幅,你可以编写:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
传递给 SpringApplication 的构造函数参数是Spring bean的配置源。在大多数情况下,
它们是对 @Configuration 类的引用,但也可以是对XML配置或应扫描的程序包的引用。
|
也可以通过使用 application.properties
文件配置 SpringApplication
。有关详细信息,请参见 外部化配置。
有关配置选项的完整列表,请参见 SpringApplication
Javadoc。
2.1.5. 流式构建器API
如果你需要构建 ApplicationContext
层次结构(具有父/子关系的多个上下文),或者如果你更喜欢使用“流式”构建器API,
则可以使用 SpringApplicationBuilder
。
SpringApplicationBuilder
使你可以将多个方法调用链接在一起,并包括允许你创建层次结构的 parent
和 child
方法,如以下示例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建 ApplicationContext 层次结构时有一些限制。例如,Web组件必须包含在子上下文中,
并且父上下文和子上下文都使用相同的 Environment 。有关完整的详细信息,请参见
SpringApplicationBuilder Javadoc 。
|
2.1.6. 应用程序事件和监听器
除了通常的Spring Framework事件(例如:
ContextRefreshedEvent
)之外,
SpringApplication
还发送一些其他应用程序事件。
实际上在创建 如果希望这些侦听器自动注册,而不管以何种方式创建应用程序,都可以将
org.springframework.context.ApplicationListener=com.example.project.MyListener |
应用程序事件在你的应用程序运行时按以下顺序发送:
-
在运行开始时但在任何处理之前(侦听器和初始化器的注册除外)发送
ApplicationStartingEvent
。 -
已知晓要在上下文中使用的环境但在创建上下文之前,将发送
ApplicationEnvironmentPreparedEvent
。 -
准备
ApplicationContext
并调用ApplicationContextInitializers之后但在加载任何bean 定义之前发送ApplicationContextInitializedEvent
。 -
在刷新开始之前但在加载bean定义之后发送
ApplicationPreparedEvent
。 -
在刷新上下文之后但在调用任何应用程序和命令行运行程序之前,将发送
ApplicationStartedEvent
。 -
在调用任何应用程序和命令行运行程序之后,将发送
ApplicationReadyEvent
。它指示该应用程序已准备就绪,可以处理请求。 -
如果启动时发生异常,则发送
ApplicationFailedEvent
。
上面的列表仅包含绑定到 SpringApplication
的 SpringApplicationEvents
。除这些以外,以下事件也在
ApplicationPreparedEvent
之后和 ApplicationStartedEvent
之前发布:
-
刷新
ApplicationContext
后发送ContextRefreshedEvent
。 -
WebServer准备就绪后,将发送
WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是servlet和reactive的变体。
你通常不需要使用应用程序事件,但是知道它们的存在可能很方便。在Spring Boot内部使用事件来处理各种任务。 |
应用程序事件是通过使用Spring Framework的事件发布机制发送的。
此机制的一部分确保在子级上下文中发布给侦听器的事件也可以在任何祖先上下文中发布给侦听器。
结果,如果你的应用程序使用 SpringApplication
实例的层次结构,则侦听器可能会收到同一类型的应用程序事件的多个实例。
为了使你的侦听器能够区分其上下文的事件和后代上下文的事件,则应请求注入其应用程序上下文,
然后将注入的上下文与事件的上下文进行比较。可以通过实现 ApplicationContextAware
来注入上下文,
或者如果侦听器是bean,则可以使用 @Autowired
注入上下文。
2.1.7. 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) 。
|
2.1.8. 访问应用程序参数
如果你需要访问传递给 SpringApplication.run(…)
的应用程序参数,
则可以注入 org.springframework.boot.ApplicationArguments
bean。ApplicationArguments
接口提供对原始
String[]
参数以及已解析的 option
和 non-option
参数的访问,如以下示例所示:
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
@Component
public class MyBean {
@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
}
}
Spring Boot还向Spring Environment 注册了 CommandLinePropertySource 。
这样,你还可以使用 @Value 注解注入单个应用程序参数。
|
2.1.9. 使用ApplicationRunner或CommandLineRunner
如果 SpringApplication
启动后需要运行一些特定的代码,则可以实现 ApplicationRunner
或 CommandLineRunner
接口。
这两个接口以相同的方式工作并提供一个 run
方法,该方法在 SpringApplication.run(…)
完成之前被调用。
CommandLineRunner
接口以简单的字符串数组提供对应用程序参数的访问,而 ApplicationRunner
使用前面讨论的
ApplicationArguments
接口。以下示例显示了带有 run
方法的 CommandLineRunner
:
import org.springframework.boot.*;
import org.springframework.stereotype.*;
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
如果定义了必须按特定顺序调用的几个 CommandLineRunner
或 ApplicationRunner
Beans,则可以另外实现
org.springframework.core.Ordered
接口或使用 org.springframework.core.annotation.Order
注解。
2.1.10. 应用程序退出
每个 SpringApplication
向JVM注册一个关闭钩子,以确保 ApplicationContext
在退出时正常关闭。
可以使用所有标准的Spring生命周期回调(例如:DisposableBean
接口或 @PreDestroy
注解)。
另外,如果bean希望在调用 SpringApplication.exit()
时返回特定的退出码,
则可以实现 org.springframework.boot.ExitCodeGenerator
接口。然后可以将此退出码传递给 System.exit()
,
以将其作为状态码返回,如以下示例所示:
@SpringBootApplication
public class ExitCodeApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
}
}
另外,ExitCodeGenerator
接口可以通过异常实现。遇到此类异常时,Spring Boot返回实现的 getExitCode()
方法提供的退出码。
2.1.11. 管理员功能
通过指定 spring.application.admin.enabled
属性,可以为应用程序启用与管理员相关的功能。
这将在平台MBeanServer上公开 SpringApplicationAdminMXBean
。
你可以使用此功能来远程管理Spring Boot应用程序。此功能对于任何服务包装器实现也可能很有用。
如果你想知道应用程序在哪个HTTP端口上运行,请使用 local.server.port 键获取属性。
|
2.2. 外部化配置
Spring Boot使你可以外部化配置,以便可以在不同环境中使用相同的应用程序代码。你可以使用properties文件,YAML文件,
环境变量和命令行参数来外部化配置。可以使用 @Value
注解将属性值直接注入到你的bean中,
可以通过Spring的 Environment
抽象访问,也可以通过 @ConfigurationProperties
绑定到结构化对象。
Spring Boot使用一个非常特殊的 PropertySource
顺序,该顺序旨在允许合理地覆盖值。按以下顺序考虑属性:
-
当devtools处于活动状态时,
$HOME/.config/spring-boot
文件夹中的 Devtools全局设置属性。 -
测试上的
@TestPropertySource
注解。 -
测试中的properties属性。在
@SpringBootTest
和测试注解上可用, 用于测试应用程序的特定部分。 -
命令行参数。
-
来自
SPRING_APPLICATION_JSON
的属性(嵌入在环境变量或系统属性中的嵌入式JSON)。 -
ServletConfig
的初始化参数。 -
ServletContext
的初始化参数。 -
来自
java:comp/env
的JNDI属性。 -
Java系统属性(
System.getProperties()
)。 -
操作系统环境变量。
-
一个
RandomValuePropertySource
仅具有random.*
属性。 -
打包jar之外的特定于profile的应用程序属性 (
application-{profile}.properties
和YAML变体)。 -
打包jar中的特定于profile的应用程序属性 (
application-{profile}.properties
和YAML变体)。 -
打包jar之外的应用程序属性(
application.properties
和YAML变体)。 -
打包jar中的应用程序属性(
application.properties
和YAML变体)。 -
@Configuration
类上的@PropertySource
注解。 请注意,在刷新应用程序上下文之前,不会将此类属性源添加到Environment
中。现在配置某些属性 (如logging.*
和spring.main.*
)为时已晚,这些属性在刷新开始之前就已读取。 -
默认属性(通过设置
SpringApplication.setDefaultProperties
指定)。
为了提供一个具体的示例,假设你开发了一个使用 name
属性的 @Component
,如以下示例所示:
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
在你的应用程序类路径上(例如:在jar中),你可以拥有一个 application.properties
文件,该文件为 name
提供合理的默认属性值。在新环境中运行时,可以在jar外部提供一个覆盖 name
的 application.properties
文件。
对于一次性测试,可以使用特定的命令行开关启动(例如:java -jar app.jar --name="Spring"
)。
可以在命令行中使用环境变量来提供 $ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar 在前面的示例中,你最终在Spring $ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar 你还可以使用命令行参数来提供JSON,如以下示例所示: $ java -jar myapp.jar --spring.application.json='{"name":"test"}' 你还可以将JSON作为JNDI变量提供,如下所示: |
2.2.1. 配置随机值
RandomValuePropertySource
可用于注入随机值(例如:注入密钥或测试用例)。它可以产生整数,longs,uuid或字符串,如以下示例所示:
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
random.int*
语法是 OPEN value (,max) CLOSE
,其中 OPEN,CLOSE
是任何字符,
而 value,max
是整数。如果提供了 max
,则 value
是最小值,而 max
是最大值(不包括它)。
2.2.2. 访问命令行Properties
默认情况下,SpringApplication
将所有命令行选项参数(即以 --
开头的参数,例如 --server.port=9000
)转换为属性,
并将其添加到Spring Environment
中。如前所述,命令行属性始终优先于其他属性源。
如果你不希望将命令行属性添加到环境中,可以使用 SpringApplication.setAddCommandLineProperties(false)
禁用它们。
2.2.3. 应用程序属性文件
SpringApplication
在以下位置从 application.properties
文件加载属性,并将它们添加到Spring Environment
:
-
当前目录的
/config
子目录 -
当前目录
-
类路径下的
/config
目录 -
类路径根目录
该列表按优先级排序(列表前面定义的属性会覆盖后面的)。
你还可以使用YAML ('.yml')文件来替代 '.properties'。 |
如果你不喜欢 application.properties
作为配置文件名,则可以通过指定 spring.config.name
环境属性来切换到另一个文件名。
你还可以通过使用 spring.config.location
环境属性(这是目录位置或以逗号分隔的文件路径列表)来显式引用位置。
下面的示例演示如何指定其他文件名:
$ java -jar myproject.jar --spring.config.name=myproject
The following example shows how to specify two locations:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
spring.config.name 和 spring.config.location 很早就被用于确定必须加载的文件。
必须将它们定义为环境属性(通常是操作系统环境变量,系统属性或命令行参数)。
|
配置位置以相反的顺序搜索。默认情况下,配置的位置是 classpath:/,classpath:/config/,file:./,file:./config/
。结果搜索顺序如下:
-
file:./config/
-
file:./
-
classpath:/config/
-
classpath:/
使用 spring.config.location
配置自定义配置位置后,它们将替换默认位置。例如:如果 spring.config.location
配置为值
classpath:custom-config/,file:./custom-config/
,则搜索顺序如下:
-
file:./custom-config/
-
classpath:custom-config/
另外,当使用 spring.config.additional-location
配置自定义配置位置时,除默认位置外,还会考虑使用它们。
在默认位置之前搜索其他附加位置。例如:如果配置了 classpath:/custom-config/,file:./custom-config/
的附加位置,则搜索顺序如下:
-
file:./custom-config/
-
classpath:custom-config/
-
file:./config/
-
file:./
-
classpath:/config/
-
classpath:/
通过此搜索顺序,你可以在一个配置文件中指定默认值,然后在另一个配置文件中有选择地覆盖这些值。
你可以在默认位置之一的 application.properties
(或使用 spring.config.name
选择的其他任何基本名称)中为应用程序提供默认值。
然后,可以在运行时使用自定义位置之一中的其他文件覆盖这些默认值。
如果使用环境变量而不是系统属性,则大多数操作系统都不允许使用句点分隔的键名,但是可以使用下划线
(例如:使用 SPRING_CONFIG_NAME 代替 spring.config.name )。
|
如果你的应用程序在容器中运行,则可以使用JNDI属性(在 java:comp/env 中)或servlet上下文初始化参数代替环境变量或系统属性。
|
2.2.4. 特定于Profile的Properties
除了 application.properties
文件之外,还可以使用以下命名约定来定义特定于profile的属性:
application-{profile}.properties
。如果没有设置激活的profile,则 Environment
具有一组默认的profiles(默认为
[default]
)。换句话说,如果未显式激活任何profiles,那么将从 application-default.properties
中加载属性。
特定于profile的属性是从与标准 application.properties
相同的位置加载的,特定于profile的文件始终会覆盖非特定文件,
而无论特定于profile的文件是位于打包jar的内部还是外部。
如果指定了多个profiles,则采用最后一个获胜策略。例如:将 spring.profiles.active
属性指定的profiles添加到通过SpringApplication API配置的profiles之后,因此具有优先权。
如果你在 spring.config.location 中指定了任何文件,则不会考虑这些文件特定于profile的变体。
如果你还想使用特定于profile的属性,请使用 spring.config.location 中的目录。
|
2.2.5. Properties中的占位符
application.properties
中的值在使用时会通过现有的 Environment
进行过滤,因此你可以参考在它之前定义的值(例如:从System属性中)。
app.name=MyApp
app.description=${app.name} is a Spring Boot application
你还可以使用这种技术来创建现有Spring Boot属性的“简短”变体。有关详细信息,请参见 使用“简短”命令行参数方法。 |
2.2.6. 加密Properties
Spring Boot不提供对加密属性值的任何内置支持,但是,它确实提供了修改Spring Environment
中包含的值所必需的钩子。
EnvironmentPostProcessor
界面允许你在应用程序启动之前操纵 Environment
。
有关详细信息,请参见 在启动前自定义环境或ApplicationContext。
如果你正在寻找一种安全的方式来存储凭据和密码, Spring Cloud Vault 项目提供了对在 HashiCorp Vault中存储外部配置的支持。
2.2.7. 使用YAML代替Properties
YAML是一个JSON超集,因此是一种用于指定层次结构配置数据的便捷格式。只要在类路径上具有
SnakeYAML库,
SpringApplication
类就会自动支持YAML作为Properties的替代方法。
如果你使用“启动器”,则 spring-boot-starter 会自动提供SnakeYAML。
|
加载YAML
Spring Framework提供了两个方便的类,可用于加载YAML文档。YamlPropertiesFactoryBean
将YAML作为 Properties
加载,
而 YamlMapFactoryBean
将YAML作为 Map
加载。
例如:考虑以下YAML文档:
environments:
dev:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App
前面的示例将转换为以下属性:
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
YAML列表用 [index]
解引用器表示为属性键。例如:考虑以下YAML:
my:
servers:
- dev.example.com
- another.example.com
前面的示例将转换为以下属性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
要通过使用Spring Boot的 Binder
实用程序(@ConfigurationProperties
所做的)绑定到类似的属性,
你需要在目标bean中拥有一个类型为 java.util.List
(或 Set
)属性,或者你需要提供一个setter或使用可变值对其进行初始化。
例如,以下示例绑定到前面显示的属性:
@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}
在Spring环境中将YAML公开为Properties
YamlPropertySourceLoader
类可用于在Spring Environment
中将YAML公开为 PropertySource
。
这样做可以让你使用 @Value
注解和占位符语法来访问YAML属性。
Multi-profile的YAML文档
你可以使用 spring.profiles
键在一个文件中指定多个特定于profile的YAML文档,以指示何时应用该文档,如以下示例所示:
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120
在前面的示例中,如果 development
profile处于激活状态,则 server.address
属性为 127.0.0.1
。
同样,如果 production
和 eu-central
profile处于激活状态,则 server.address
属性为 192.168.1.120
。
如果 未 启用 development
, production
和 eu-central
profiles,则该属性的值为 192.168.1.100
。
因此 |
如果在启动应用程序上下文时未明确激活任何profiles,则会激活默认的profiles。因此,在以下YAML中,我们为
spring.security.user.password
设置了一个值,该值 仅 在 "default" profile中可用:
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
而在以下示例中,则会始终设置密码是因为该密码未附加到任何profile,并且必须根据需要在所有其他profiles中将其显式重置:
server:
port: 8000
spring:
security:
user:
password: weak
使用 spring.profiles
元素指定的Spring profiles可以选择使用 !
字符来否定。如果为单个文档指定了否定的和非否定的profiles,
则至少一个非否定的profile必须匹配,并且否定的profiles不能匹配。
YAML的缺点
无法使用 @PropertySource
注解加载YAML文件。因此,在需要以这种方式加载值的情况下,需要使用properties文件。
在特定于profile的YAML文件中使用多YAML文档语法可能会导致意外行为。例如:考虑文件中的以下配置:
server:
port: 8000
---
spring:
profiles: "!test"
security:
user:
password: "secret"
如果使用参数 --spring.profiles.active=dev
运行该应用程序,则可能希望将 security.user.password
设置为“secret
”,但事实并非如此。
嵌套文档将被过滤,因为主文件名为 application-dev.yml
。它已经被认为是特定于profile的,并且嵌套文档将被忽略。
我们建议你不要混用特定于profile的YAML文件和多个YAML文档。坚持只使用其中之一。 |
2.2.8. 类型安全的配置Properties
使用 @Value("${property}")
注解来注入配置属性有时会很麻烦,尤其是当你使用多个properties或数据本质上是分层的时。
Spring Boot提供了一种使用属性的替代方法,使用强类型的properties bean来管理和验证应用程序的配置。
JavaBean properties绑定
可以绑定一个声明标准JavaBean属性的bean,如以下示例所示:
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}
前面的POJO定义了以下属性:
-
acme.enabled
,默认值为false
。 -
acme.remote-address
,其类型可以从String
强制转换。 -
acme.security.username
,带有嵌套的“security”对象,其名称由属性名称确定。 特别是,返回类型根本没有使用,也可能是SecurityProperties
。 -
acme.security.password
。 -
acme.security.roles
,带有默认拥有单个USER
的String
集合。
Spring Boot自动配置大量使用 @ConfigurationProperties 来轻松配置自动配置的bean。
与自动配置类相似,Spring Boot中可用的 @ConfigurationProperties 类仅供内部使用。
通过Properties文件、YAML文件、环境变量等配置映射到的类属性是公共API,但是该类本身的内容并不意味着可以直接使用。
|
这种自动配置依赖于默认的空构造函数,并且getter和setter通常是强制性的,因为绑定是通过标准Java Beans属性描述符进行的, 就像在Spring MVC中一样。在以下情况下,可以忽略setter:
有些人使用Lombok项目自动添加getters和setters。确保Lombok不会为这种类型生成任何特定的构造函数,因为容器会自动使用它来实例化该对象。 最后,仅考虑标准Java Bean属性,不支持对静态属性的绑定。 |
构造函数绑定
上一节中的示例可以用不可变的方式重写,如下例所示:
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
在此设置中,@ConstructorBinding
注解用于指示应使用构造函数绑定。这意味着绑定器将期望找到带有你希望绑定的参数的构造函数。
@ConstructorBinding
类的嵌套成员(例如上例中的 Security
)也将通过其构造函数进行绑定。
可以使用 @DefaultValue
指定默认值,并且将应用相应的转换服务将 String
值强制转换为缺失属性的目标类型。
要使用构造函数绑定,必须使用 @EnableConfigurationProperties 或配置属性扫描来启用该类。你不能对通过常规Spring机制创建的bean
使用构造函数绑定(例如:@Component bean,通过 @Bean 方法创建的bean或使用 @Import 加载的bean)。
|
如果你的类具有多个构造函数,则还可以直接在应绑定的构造函数上使用 @ConstructorBinding 。
|
启用被 @ConfigurationProperties
注解的类型
Spring Boot提供了绑定 @ConfigurationProperties
类型并将其注册为Bean的基础设施。
你可以逐类启用配置属性,也可以启用与组件扫描类似的方式进行配置属性扫描。
有时,用 @ConfigurationProperties
注解的类可能不适用于扫描,例如:如果你正在开发自己的自动配置,
或者想要有条件地启用它们。在这些情况下,请使用 @EnableConfigurationProperties
注解指定要处理的类型列表。
可以在任何 @Configuration
类上完成此操作,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
要使用配置属性扫描,请将 @ConfigurationPropertiesScan
注解添加到你的应用程序。
通常,它被添加到使用 @SpringBootApplication
注解的主应用程序类中,但可以将其添加到任何 @Configuration
类中。
默认情况下,将从声明注解的类的包中进行扫描。如果要定义待扫描的特定程序包,可以按照以下示例所示进行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
When the 使用配置属性扫描或通过 上例中的bean名称是 |
我们建议 @ConfigurationProperties
仅处理环境,尤其不要从上下文中注入其他bean。
对于极端情况,可以使用setter注入或框架提供的任何 *Aware
接口(例如:需要访问 Environment
的 EnvironmentAware
)。
如果仍然想使用构造函数注入其他bean,则必须使用 @Component
注解配置properties bean,并使用基于JavaBean的属性绑定。
使用被 @ConfigurationProperties
注解的类型
这种配置方式在 SpringApplication
外部的YAML配置中特别好用,如以下示例所示:
# application.yml
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
# additional configuration as required
要与 @ConfigurationProperties
Bean一起使用,可以像其他任何Bean一样注入它们,如以下示例所示:
@Service
public class MyService {
private final AcmeProperties properties;
@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}
使用 @ConfigurationProperties 还可让你生成元数据文件,IDE可以使用这些元数据文件为你自己的键提供自动完成功能。
有关详细信息,请参见 附录。
|
第三方配置
除了使用 @ConfigurationProperties
注解类外,还可以在public @Bean
方法上使用它。当你要将属性绑定到控件之外的第三方组件时,这样做特别有用。
要从 Environment
属性配置Bean,请将 @ConfigurationProperties
添加到其Bean注册中,如以下示例所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
用 another
前缀定义的任何JavaBean属性都以类似于前面的 AcmeProperties
示例的方式映射到该 AnotherComponent
bean。
宽松绑定
Spring Boot使用一些宽松的规则将 Environment
属性绑定到 @ConfigurationProperties
bean,
因此 Environment
属性名称和bean属性名称之间不需要完全匹配。有用的常见示例包括:以破折号分隔的环境属性
(例如:context-path
绑定到 contextPath
)和大写的环境属性(例如:PORT
绑定到 port
)。
例如:考虑以下 @ConfigurationProperties
类:
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
使用前面的代码,以下属性名称均可以使用:
属性 | 说明 |
---|---|
|
Kebab格式,建议在 |
|
标准小驼峰式语法。 |
|
下划线表示法,是 |
|
大写格式,使用系统环境变量时建议使用。 |
注解的前缀值 必须 为kebab格式(小写,并用 - 分隔,例如:acme.my-project.person )。
|
属性源 | 支持 | 列表 |
---|---|---|
Properties文件 |
小驼峰,kebab或下划线表示法 |
使用 |
YAML文件 |
小驼峰,kebab或下划线表示法 |
Standard YAML list syntax or comma-separated values |
环境变量 |
以下划线作为定界符的大写格式。 |
下划线包围的数值,例如: |
系统属性 |
小驼峰,kebab或下划线表示法 |
使用 |
我们建议,如果可能,属性以小写kebab格式存储,例如:my.property-name=acme 。
|
绑定到 Map
属性时,如果 key
包含小写字母数字字符或 -
以外的任何其他字符,则需要使用方括号表示法,以便保留原始值。
如果键没有被 []
包围,则所有非字母数字或 -
字符都将被删除。例如,考虑将以下属性绑定到 Map
:
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3
上面的属性将以 /key1
,/key2
和 key3
作为映射中的键被绑定到 Map
。
对于YAML文件,方括号需要用引号引起来,以便正确解析。 |
合并复杂类型
如果在多个地方配置了列表,则通过替换整个列表来进行覆盖。
例如:假设 MyPojo
对象的 name
和 description
属性默认为 null
。
下面的示例从 AcmeProperties
公开 MyPojo
对象的列表:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考虑以下配置:
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name
如果 dev
profile未处于激活状态,则 AcmeProperties.list
包含一个 MyPojo
条目,如先前所定义。
但是,如果启用了 dev
profile,则该列表仍然仅包含一个条目(名称为 my another name
,并且描述为 null
)。
此配置 不会 将第二个 MyPojo
实例添加到列表中,并且不会合并条目。
在多个profiles中指定 List
时,将使用优先级最高的列表(并且仅使用那个列表)。考虑以下示例:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name
在前面的示例中,如果 dev
profile处于激活状态,则 AcmeProperties.list
包含一个 MyPojo
条目
(其名称为 my another name
,并且描述为 null
)。对于YAML,可以使用逗号分隔的列表和YAML列表来完全覆盖列表的内容。
对于 Map
属性,可以绑定从多个来源绘制的属性值。但是,对于多个源中的同一属性,将使用优先级最高的属性。
下面的示例从 AcmeProperties
公开 Map<String, MyPojo>
:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
考虑以下配置:
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
如果 dev
profile未处于激活状态,则 AcmeProperties.map
包含一个键为key1的条目(名称为 my name 1
,描述为 my description 1
)。
但是,如果启用了 dev
profile,则map包含两个条目,其中键为key1的条目(名称为 dev name 1
,描述为 my description 1
)
和key2(名称为 dev name 2
,描述为 dev description 2
)。
前述合并规则不仅适用于YAML文件,而且适用于所有属性源中的属性。 |
属性转换
当Spring Boot绑定到 @ConfigurationProperties
bean时,它尝试将外部应用程序属性强制为正确的类型。
如果需要自定义类型转换,则可以提供一个 ConversionService
bean(具有一个名为 conversionService
的bean)
或自定义属性编辑器(通过 CustomEditorConfigurer
bean)或自定义 Converters
(具有定义为 @ConfigurationPropertiesBinding
的bean定义)。
由于在应用程序生命周期中非常早就请求了此bean,因此请确保限制你的 ConversionService 使用的依赖项。
通常,你需要的任何依赖项可能在创建时未完全初始化。如果配置键强制转换不需要自定义的转换服务,则可能要重命名自定义的
ConversionService 且它仅依赖于具有 @ConfigurationPropertiesBinding 限定的自定义转换器。
|
转换持续时间
Spring Boot为表达持续时间提供了专门的支持。如果公开 java.time.Duration
属性,则应用程序属性中的以下格式可用:
-
常规的
long
表示形式(使用毫秒作为默认单位,除非已指定@DurationUnit
) -
java.time.Duration
使用的标准ISO-8601格式 -
值和单位相结合的更易读的格式(例如:10s表示10秒)
考虑以下示例:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
要指定30秒的会话超时,则 30
,PT30S
和 30s
都是等效的。可以使用以下任意形式指定500ms的读取超时:
500
,PT0.5S
和 500ms
。
你也可以使用任何受支持的单位:
-
ns
纳秒 -
us
微秒 -
ms
毫秒 -
s
秒 -
m
分钟 -
h
小时 -
d
天
默认单位是毫秒,可以使用 @DurationUnit
覆盖,如上面的示例所示。
如果你要从仅使用 Long 表示持续时间的先前版本进行升级,原单位若不是毫秒那么请确保在切换到 Duration
时指定单位(使用 @DurationUnit )。这样做可以提供透明的升级路径,同时支持更丰富的格式。
|
转换数据大小
Spring Framework具有 DataSize
值类型,以字节为单位表示大小。如果公开 DataSize
属性,则应用程序属性中的以下格式可用:
-
常规的
long
表示形式(除非已指定@DataSizeUnit
,否则使用字节作为默认单位) -
值和单位耦合在一起的更易读的格式(例如:10MB表示10兆字节)
考虑以下示例:
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
public DataSize getBufferSize() {
return this.bufferSize;
}
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
}
}
若要指定10 MB的缓冲区大小,则 10
和 10MB
是等效的。256个字节大小的阈值可以指定为 256
或 256B
。
你也可以使用任何受支持的单位:
-
B
字节 -
KB
千字节 -
MB
兆字节 -
GB
千兆字节 -
TB
兆兆字节
默认单位是字节,可以使用 @DataSizeUnit
覆盖,如上面的示例所示。
如果要从仅使用 Long 表示大小的先前版本进行升级,原单位若不是字节那么请确保在切换到 DataSize
时指定单位(使用 @DataSizeUnit )。这样做可以提供透明的升级路径,同时支持更丰富的格式。
|
@ConfigurationProperties验证
每当使用Spring的 @Validated
注解对 @ConfigurationProperties
类进行批注时,
Spring Boot就会尝试对其进行验证。你可以在配置类上直接使用JSR-303 javax.validation
约束注解。
为此,请确保在类路径上有兼容的JSR-303实现,然后将约束注解添加到字段中,如以下示例所示:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
你还可以通过使用 @Validated 注解创建配置属性的 @Bean 方法来触发验证。
|
为了确保始终为嵌套属性触发验证,即使未找到任何属性,也必须使用 @Valid
注解关联的字段。下面的示例基于前面的 AcmeProperties
示例:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}
你还可以通过创建一个名为 configurationPropertiesValidator
的bean定义来添加自定义Spring Validator
。
@Bean
方法应声明为 static
。配置属性验证器是在应用程序生命周期的早期创建的,
并且将 @Bean
方法声明为 static
可以使创建该bean而不必实例化 @Configuration
类。这样做避免了由早期实例化引起的任何问题。
spring-boot-actuator 模块包括一个公开所有 @ConfigurationProperties beans的端点。
将你的Web浏览器指向 /actuator/configprops 或使用等效的JMX端点访问。有关详细信息,请参见“
生产就绪功能”部分。
|
@ConfigurationProperties vs @Value
@Value
注解是核心容器功能,它没有提供与类型安全的配置属性相同的功能。
下表总结了 @ConfigurationProperties
和 @Value
支持的功能:
功能 | @ConfigurationProperties |
@Value |
---|---|---|
Yes |
No |
|
Yes |
No |
|
|
No |
Yes |
如果你为自己的组件定义了一组配置键,我们建议你将它们组合在以 @ConfigurationProperties
注解的POJO中。
你还应该意识到,由于 @Value
不支持宽松的绑定,因此如果你需要使用环境变量来提供值,则它不是一个很好的选择。
最后,尽管你可以在 @Value
中编写SpEL表达式,但不会从应用程序属性文件中处理此类表达式。
2.3. Profiles
Spring Profiles提供了一种隔离应用程序配置部分并使之仅在某些环境中可用的方法。
任何 @Component
,@Configuration
或 @ConfigurationProperties
都可以用 @Profile
标记以限制其加载时间,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {
// ...
}
如果 @ConfigurationProperties Bean是通过 @EnableConfigurationProperties 而非自动扫描注册的,
则需要在具有 @EnableConfigurationProperties 注解的 @Configuration 类上指定 @Profile 注解。
在自动扫描 @ConfigurationProperties 的情况下,可以在 @ConfigurationProperties 类本身上指定 @Profile 。
|
你可以使用 spring.profiles.active
环境属性来指定哪些配置文件处于激活状态。你可以通过本章前面介绍的任何方式指定属性。
例如,你可以将其包含在 application.properties
中,如以下示例所示:
spring.profiles.active=dev,hsqldb
你也可以使用以下开关在命令行上指定它:--spring.profiles.active=dev,hsqldb
。
2.3.1. 添加活动Profiles
spring.profiles.active
属性遵循与其他属性相同的排序规则:最高的 PropertySource
获胜。这意味着你可以在
application.properties
中指定要激活配置文件,然后使用命令行开关 替换 它们。
有时,将特定于profile的属性 添加 到活动profiles而不是替换它们很有用。
spring.profiles.include
属性可用于无条件添加活动Profiles。SpringApplication
入口点还具有Java API,
用于设置其他附加的profiles(即在由 spring.profiles.active
属性激活的profiles之上)。
参见 SpringApplication中的 setAdditionalProfiles()
方法。
例如,当使用开关 --spring.profiles.active=prod
运行具有以下属性的应用程序时,proddb
和 prodmq
配置文件也会被激活:
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq
请记住,可以在YAML文档中定义 spring.profiles 属性,以确定该特定文档何时包含在配置中。有关更多详细信息,请参见
根据环境更改配置。
|
2.3.2. 以编程方式设置Profiles
你可以在应用程序运行之前通过调用 SpringApplication.setAdditionalProfiles(…)
以编程方式设置活动配置文件。
也可以使用Spring的 ConfigurableEnvironment
接口来激活profiles。
2.3.3. 特定于Profile的配置文件
application.properties
(或 application.yml
)和通过
@ConfigurationProperties
所引用文件的特定于profile的变体都会被视为配置文件并加载。
有关详细信息,请参见“特定于Profile的Properties”。
2.4. 日志
Spring Boot使用 Commons Logging进行所有内部日志记录,但是使底层日志实现保持打开状态。 提供了 Java Util Logging, Log4J2和 Logback的默认配置。 在每种情况下,日志记录器都已预先配置为使用控制台输出,同时还提供可选的文件输出。
默认情况下,如果使用“Starters
”,则使用Logback进行日志记录。还包括适当的Logback路由,以确保使用
Java Util Logging,Commons Logging,Log4J或SLF4J的从属库都可以正常工作。
Java有许多可用的日志记录框架。如果上面的列表看起来令人困惑,请不要担心。 通常,你不需要更改日志记录依赖项,并且Spring Boot默认值可以正常工作。 |
将应用程序部署到Servlet容器或应用程序服务器时,通过Java Util Logging API执行的日志记录不会路由到应用程序的日志中。 这样可以防止容器或其他已部署到容器中的应用程序执行的日志记录出现在应用程序的日志中。 |
2.4.1. 日志格式
Spring Boot的默认日志输出类似于以下示例:
2019-03-05 10:57:51.112 INFO 45469 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/7.0.52 2019-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms 2019-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] 2019-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
默认输出以下条目:
-
日期和时间:毫秒精度,易于分类。
-
日志级别:
ERROR
,WARN
,INFO
,DEBUG
和TRACE
。 -
进程ID。
-
---
分隔符用于区分实际日志消息的开始。 -
线程名:用方括号括起来(对于控制台输出,可能会被截断)。
-
记录器名称:这通常是源类名称(通常是缩写格式)。
-
日志消息。
Logback没有 FATAL 日志级别。它被映射到 ERROR 。
|
2.4.2. 控制台输出
默认日志配置在消息写入时将消息回显到控制台。默认情况下,将记录 ERROR
级别,WARN
级别和 INFO
级别的消息。
你还可以通过使用 --debug
标志启动应用程序来启用“debug
”模式。
$ java -jar myapp.jar --debug
你还可以在 application.properties 中指定 debug=true 。
|
启用调试模式后,将配置一些核心日志记录器(嵌入式容器,Hibernate和Spring Boot)以输出更多信息。
启用调试模式 不会 将你的应用程序配置为记录所有具有 DEBUG
级别的消息。
或者,你可以通过使用 --trace
标志(或 application.properties
中的 trace=true
)启动应用程序来启用“trace
”模式。
这样做可以为某些核心记录器(嵌入式容器,Hibernate schema生成以及整个Spring产品组合)启用跟踪记录。
颜色编码输出
如果你的终端支持ANSI,则使用彩色输出来提高可读性。你可以将 spring.output.ansi.enabled
设置为
支持的值,以覆盖自动检测。
使用 %clr
转换字配置颜色编码。转换器以最简单的形式根据日志级别为输出着色,如以下示例所示:
%clr(%5p)
下表描述了日志级别到颜色的映射:
Level | Color |
---|---|
|
红色 |
|
红色 |
|
黄色 |
|
绿色 |
|
绿色 |
|
绿色 |
另外,你可以通过将其提供为转换的选项来指定应使用的颜色或样式。例如:要使文本变黄,请使用以下设置:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
支持以下颜色和样式:
-
blue
-
cyan
-
faint
-
green
-
magenta
-
red
-
yellow
2.4.3. 文件输出
默认情况下,Spring Boot仅记录到控制台,不写日志文件。如果除了控制台输出外还想写日志文件,
则需要设置 logging.file.name
或 logging.file.path
属性(例如:在 application.properties
中)。
下表显示了如何结合使用 logging.*
属性:
logging.file.name |
logging.file.path |
示例 | 描述 |
---|---|---|---|
(none) |
(none) |
仅控制台记录。 |
|
特定文件 |
(none) |
|
写入指定的日志文件。名称可以是确切位置,也可以是相对于当前目录的位置。 |
(none) |
特定目录 |
|
将 |
日志文件达到10 MB时会旋转,并且与控制台输出一样,默认情况下会记录 ERROR
级别,WARN
级别和 INFO
级别的消息。
可以使用 logging.file.max-size
属性更改大小限制。除非已设置 logging.file.max-history
属性,
否则以前旋转的文件将无限期存档。可以使用 logging.file.total-size-cap
限制日志归档文件的总大小。
当日志归档的总大小超过该阈值时,将删除备份。要在应用程序启动时强制清除日志归档文件,
请使用 logging.file.clean-history-on-start
属性。
日志记录属性独立于实际的日志记录基础设施。因此,特定的配置键(例如:Logback的 logback.configurationFile )不是由Spring Boot管理的。
|
2.4.4. 日志级别
通过使用 logging.level.<logger-name>=<level>
可以在Spring Environment
中(例如:在 application.properties
中)
设置所有受支持的日志记录器级别。其中 level
是TRACE, DEBUG, INFO, WARN, ERROR, FATAL 或 OFF。
可以使用 logging.level.root
配置 root
记录器。
以下示例显示了 application.properties
中的潜在日志记录设置:
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
也可以使用环境变量设置日志记录级别。例如:LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
会将
org.springframework.web
设置为 DEBUG
。
以上方法仅适用于程序包级别的日志记录。由于宽松的绑定总是将环境变量转换为小写,因此无法以这种方式为单个类配置日志记录。
如果需要为类配置日志记录,则可以使用SPRING_APPLICATION_JSON 变量。
|
2.4.5. 日志组
能够将相关记录器分组在一起通常是很有用的,以便可以同时配置它们。例如:你可能通常会更改 所有 与Tomcat相关的记录器的日志级别,但是你不容易记住顶层软件包。
为了解决这个问题,Spring Boot允许你在Spring Environment
中定义日志记录组。例如:以下是通过将“tomcat
”组添加到
application.properties
来定义它的方法:
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
定义后,你可以仅使用一行就更改该组中所有记录器的日志级别:
logging.level.tomcat=TRACE
Spring Boot包含以下预定义的日志记录组,它们可以直接使用:
名称 | 记录器 |
---|---|
web |
|
sql |
|
2.4.6. 自定义日志配置
可以通过在类路径中包括适当的库来激活各种日志记录系统,并可以通过在类路径的根目录中或在以下Spring
Environment
属性指定的位置中提供适当的配置文件来进一步自定义日志文件:logging.config
。
你可以通过使用 org.springframework.boot.logging.LoggingSystem
系统属性来强制Spring Boot使用特定的日志记录系统。
该值应该是 LoggingSystem
实现的完全限定类名。你也可以使用 none
值完全禁用Spring Boot的日志记录配置。
由于日志记录是在创建 ApplicationContext 之前 初始化的,因此无法从Spring
@Configuration 文件中的 @PropertySources 控制日志记录。更改日志记录系统或完全禁用它的唯一方法是通过系统属性。
|
根据你的日志记录系统,将加载以下文件:
志记录系统 | 自定义配置文件 |
---|---|
Logback |
|
Log4j2 |
|
JDK (Java Util Logging) |
|
如果可能,我们建议你在日志配置中使用 -spring 变体(例如:使用 logback-spring.xml 而不是 logback.xml )。
如果使用标准配置位置,Spring将无法完全控制日志初始化。
|
在“可执行jar”运行时,Java Util Logging存在一些已知的类加载问题,这会引起问题。我们建议你尽可能在“可执行jar”运行时避免使用它。 |
为了帮助定制,将一些其他属性从Spring Environment
转移到系统属性,如下表所述:
Spring Environment | System Property | 说明 |
---|---|---|
|
|
记录异常时使用的转换字。 |
|
|
是否在启动时清除存档日志文件(如果启用了LOG_FILE)。(仅默认的Logback设置受支持。) |
|
|
如果定义,它将在默认日志配置中使用。 |
|
|
最大日志文件大小(如果启用了LOG_FILE)。(仅默认的Logback设置受支持。) |
|
|
要保留的最大归档日志文件数(如果启用了LOG_FILE)。(仅默认的Logback设置受支持。) |
|
|
如果定义,它将在默认日志配置中使用。 |
|
|
要保留的备份日志的总大小(如果启用了LOG_FILE)。(仅默认的Logback设置受支持。) |
|
|
控制台上使用的日志模式(stdout)。(仅默认的Logback设置受支持。) |
|
|
记录日期格式的附加模式。(仅默认的Logback设置受支持。) |
|
|
文件中使用的日志模式(如果启用了LOG_FILE)。(仅默认的Logback设置受支持。) |
|
|
呈现日志级别时使用的格式(默认为 |
|
|
过渡日志文件名的模式(默认为 |
|
|
当前进程ID(如果可能,并且尚未将其定义为操作系统环境变量时将被发现)。 |
所有受支持的日志记录系统在解析其配置文件时都可以查阅系统属性。有关示例,请参见 spring-boot.jar
中的默认配置:
如果要在日志记录属性中使用占位符,则应使用Spring Boot的语法而不是基础框架的语法。
值得注意的是,如果使用Logback,则应使用 |
你可以通过仅覆盖 2019-08-30 12:30:04.031 user:someone INFO 22174 --- [ nio-8080-exec-0] demo.Controller Handling authenticated request |
2.4.7. Logback扩展
Spring Boot包含许多Logback扩展,可以帮助进行高级配置。你可以在 logback-spring.xml
配置文件中使用这些扩展名。
由于标准 logback.xml 配置文件加载得太早,因此无法在其中使用扩展名。你需要使用 logback-spring.xml 或定义 logging.config 属性。
|
这些扩展不能与Logback的 配置扫描一起使用。 如果尝试这样做,则对配置文件进行更改将导致类似于以下日志之一的错误: |
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]] ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
特定于Profile的配置
通过 <springProfile>
标记,你可以根据活动的Spring profiles有选择地包括或排除配置部分。
在 <configuration>
元素内的任何位置都支持profile部分。使用 name
属性指定哪个profile接受配置。
<springProfile>
标记可以包含简单的profile名称(例如:staging
)或profile表达式。
profile表达式允许表达更复杂的配置文件逻辑,例如:production & (eu-central | eu-west)
。
有关更多详细信息,请参阅 参考指南。
以下清单显示了三个样本profiles:
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
环境属性
<springProperty>
标签使你可以从Spring Environment
中公开属性,以在Logback中使用。
如果要在Logback配置中访问 application.properties
文件中的值,则这样做很有用。
该标签的工作方式类似于Logback的标准 <property>
标签。但是,不是指定直接 value
,而是指定属性的 source
(来自 Environment
)。
如果需要将属性存储在 local
作用域以外的其他位置,则可以使用 scope
属性。如果需要后备值(如果未在环境中设置该属性),
则可以使用 defaultValue
属性。以下示例显示如何公开在Logback中使用的属性:
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
...
</appender>
source 必须以kebab格式指定(例如:my.property-name )。但是,可以使用宽松的规则将属性添加到 Environment 中。
|
2.5. 国际化
Spring Boot支持本地化消息,因此你的应用程序可以迎合不同语言首选项的用户。
默认情况下,Spring Boot在类路径的根目录下查找存在的 messages
资源包。
当已配置资源束的默认属性文件可用时(即默认情况下为 messages.properties ),将应用自动配置。
如果你的资源包仅包含特定于语言的属性文件,则需要添加默认文件。如果找不到与任何配置的基本名称匹配的属性文件,将没有自动配置的 MessageSource 可用。
|
可以使用 spring.messages
命名空间配置资源包的基本名称以及其他几个属性,如以下示例所示:
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
spring.messages.basename 支持以逗号分隔的位置列表,可以是包限定符,也可以是从类路径根目录解析的资源。
|
有关更多受支持的选项,请参见 MessageSourceProperties
。
2.6. JSON
Spring Boot提供了与三个JSON映射库的集成:
-
Gson
-
Jackson
-
JSON-B
Jackson是首选的默认库。
2.6.1. Jackson
提供了Jackson的自动配置,并且Jackson是 spring-boot-starter-json
的一部分。当Jackson放在类路径上时,
将自动配置 ObjectMapper
Bean。提供了几个配置属性,用于
自定义 ObjectMapper
的配置。
2.6.2. Gson
提供了Gson的自动配置。当Gson在类路径上时,将自动配置 Gson
bean。提供了几个 spring.gson.*
配置属性用于自定义配置。为了获得更多控制权,可以使用一个或多个 GsonBuilderCustomizer
bean。
2.6.3. JSON-B
提供了JSON-B的自动配置。当JSON-B API和实现位于类路径上时,将自动配置 Jsonb
bean。首选的JSON-B实现是提供了依赖管理的
Apache Johnzon。
2.7. 开发Web应用程序
Spring Boot非常适合于Web应用程序开发。你可以使用嵌入式Tomcat,Jetty,Undertow或Netty创建独立的HTTP服务器。
大多数Web应用程序都使用 spring-boot-starter-web
模块来快速启动和运行。
你还可以选择使用 spring-boot-starter-webflux
模块构建响应式Web应用程序。
2.7.1. Spring Web MVC框架
Spring Web MVC框架
(通常简称为“Spring MVC”)是一个丰富的“model view controller
”Web框架。
Spring MVC使你可以创建特殊的 @Controller
或 @RestController
Bean来处理传入的HTTP请求。
使用 @RequestMapping
注解将控制器中的方法映射到HTTP。
以下代码显示了提供JSON数据返回的典型 @RestController
:
@RestController
@RequestMapping(value="/users")
public class MyRestController {
@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}
}
Spring MVC是核心Spring Framework的一部分,有关详细信息,请参阅 参考文档。 在 spring.io/guides 上还有一些涵盖Spring MVC的指南。
Spring MVC自动配置
Spring Boot为Spring MVC提供了自动配置,可与大多数应用程序完美配合。
自动配置在Spring的默认设置之上添加了以下功能:
-
包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
Bean。 -
支持服务静态资源,包括对WebJars的支持(在本文档后面介绍)。
-
自动注册
Converter
,GenericConverter
和Formatter
Bean。 -
对
HttpMessageConverters
的支持(在本文档后面介绍)。 -
自动注册
MessageCodesResolver
(在本文档后面介绍)。 -
静态
index.html
支持。 -
自定义
Favicon
支持(在本文档后面介绍)。 -
自动使用
ConfigurableWebBindingInitializer
Bean(在本文档后面介绍)。
如果你想保留Spring Boot MVC功能并想要添加其他 MVC配置(拦截器,格式化程序,视图控制器和其他功能),
则可以添加自己的类型为 WebMvcConfigurer
的 @Configuration
类,但 不添加 @EnableWebMvc
。
如果希望提供 RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
或
ExceptionHandlerExceptionResolver
的自定义实例,则可以声明一个 WebMvcRegistrationsAdapter
实例以提供此类组件。
如果要完全控制Spring MVC,则可以添加自己的带有 @EnableWebMvc
注解的 @Configuration
类。
HttpMessageConverters
Spring MVC使用 HttpMessageConverter
接口转换HTTP请求和响应。开箱即用中包含明智的默认设置。
例如:可以将对象自动转换为JSON(通过使用Jackson库)或XML(如果可用通过使用Jackson XML扩展或如果Jackson
XML扩展不可用通过使用JAXB)。默认情况下,字符串以 UTF-8
编码。
如果你需要添加或自定义转换器,则可以使用Spring Boot的 HttpMessageConverters
类,如以下清单所示:
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
上下文中存在的所有 HttpMessageConverter
bean都将添加到转换器列表中。你也可以用相同的方法覆盖默认转换器。
自定义JSON序列化器和反序列化器
如果使用Jackson序列化和反序列化JSON数据,则可能要编写自己的 JsonSerializer
和 JsonDeserializer
类。
自定义序列化程序通常是 通过模块向Jackson进行注册的,
但是Spring Boot提供了替代的 @JsonComponent
注解,这使得直接注册Spring Bean更加容易。
你可以直接在 JsonSerializer
,JsonDeserializer
或 KeyDeserializer
实现上使用 @JsonComponent
注解。
你还可以在包含序列化器/反序列化器作为内部类的类上使用它,如以下示例所示:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}
}
ApplicationContext
中的所有 @JsonComponent
bean都会自动向Jackson注册。
因为 @JsonComponent
用 @Component
进行元注解,所以适用常规的组件扫描规则。
Spring Boot还提供了 JsonObjectSerializer
和 JsonObjectDeserializer
基类,
这些基类在序列化对象时为标准Jackson版本提供了有用的替代方法。有关详细信息,请参见Javadoc中的
JsonObjectSerializer
和
JsonObjectDeserializer
。
MessageCodesResolver
Spring MVC有一种生成错误码以从绑定错误中呈现错误消息的策略:MessageCodesResolver
。
如果你设置 spring.mvc.message-codes-resolver-format
属性为 PREFIX_ERROR_CODE
或 POSTFIX_ERROR_CODE
,
Spring Boot会为你创建一个(请参见 DefaultMessageCodesResolver.Format
中的枚举)。
静态内容
默认情况下,Spring Boot从类路径中的 /static
目录(或 /public
或 /resources
或 /META-INF/ resources
)
或ServletContext的根目录中提供静态内容。它使用Spring MVC中的 ResourceHttpRequestHandler
,
以便你可以通过添加自己的 WebMvcConfigurer
并重写 addResourceHandlers
方法来修改该行为。
在独立的Web应用程序中,还启用了容器中的默认Servlet,并将其用作降级方案,如果Spring决定不处理,
则从 ServletContext
的根目录提供内容。在大多数情况下,这不会发生(除非你修改默认的MVC配置),
因为Spring始终可以通过 DispatcherServlet
处理请求。
默认情况下,资源映射在 /**
上,但是你可以使用 spring.mvc.static-path-pattern
属性进行调整。
例如:将所有资源重定位到 /resources/**
可以按如下方式实现:
spring.mvc.static-path-pattern=/resources/**
你还可以使用 spring.resources.static-locations
属性来自定义静态资源位置(用目录位置列表替换默认值)。
根Servlet上下文路径 "/"
也会作为位置自动添加。
除了前面提到的“标准”静态资源位置, Webjars 内容还有一个特殊情况。
如果jar文件以Webjars格式打包,则从jar文件提供带有 /webjars/**
路径的所有资源。
如果你的应用程序打包为jar,则不要使用 src/main/webapp 目录。尽管此目录是一个通用标准,
但它仅与war打包一起使用,并且如果生成jar,大多数构建工具都将其忽略。
|
Spring Boot还支持Spring MVC提供的高级资源处理功能,允许使用案例如:缓存清除静态资源或对Webjars使用版本无关的URL。
要对Webjars使用版本无关的URL,请添加 webjars-locator-core
依赖项,然后声明你的Webjar。
以jQuery为例,添加 "/webjars/jquery/jquery.min.js"
将得到 "/webjars/jquery/x.y.z/jquery.min.js"
,
其中 x.y.z
是Webjar版本。
如果使用JBoss,则需要声明 webjars-locator-jboss-vfs 依赖项,而不是 webjars-locator-core 。
否则,所有Webjar都解析为 404 。
|
要使用缓存清除,以下配置为所有静态资源配置了缓存清除解决方案,并在URL中有效地添加了内容哈希,例如:
<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
通过为Thymeleaf和FreeMarker自动配置 ResourceUrlEncodingFilter ,可以在运行时在模板中重写到资源的链接。
使用JSP时,你应该手动声明此过滤器。当前尚不自动支持其他模板引擎,但可以与自定义模板宏/帮助器一起使用,以及使用
ResourceUrlProvider 。
|
例如:当使用JavaScript模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也受支持并且可以相互组合的原因。 “固定”策略在URL中添加静态版本字符串,而不更改文件名,如以下示例所示:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
通过这种配置,位于 "/js/lib/"
下的JavaScript模块使用固定的版本控制策略("/v12/js/lib/mymodule.js"
),
而其他资源仍使用内容版本(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
)。
有关更多受支持的选项,请参见 ResourceProperties
。
欢迎页面
Spring Boot支持静态和模板欢迎页面。它首先在配置的静态内容位置中查找 index.html
文件。如果未找到,则寻找 index
模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。
自定义图标
与其他静态资源一样,Spring Boot在已配置的静态内容位置中查找 favicon.ico
。如果存在这样的文件,它将自动用作应用程序的收藏夹图标。
路径匹配和内容协商
Spring MVC可以通过查看请求路径并将其匹配到应用程序中定义的映射(例如:Controller方法上的 @GetMapping
注解)来将传入的HTTP请求映射到处理程序。
Spring Boot选择默认情况下禁用后缀模式匹配,这意味着 "GET /projects/spring-boot.json"
之类的请求将不会与
@GetMapping("/projects/spring-boot")
映射进行匹配。这被认为是
Spring MVC应用程序的最佳实践。
过去,此功能主要用于未发送正确的“Accept”请求头的HTTP客户端,我们需要确保将正确的内容类型发送给客户端。
如今,内容协商已变得更加可靠。
还有其他处理HTTP客户端的方法,这些客户端不能始终发送正确的“Accept”请求头。
除了使用后缀匹配,我们还可以使用查询参数来确保将诸如 "GET /projects/spring-boot?format=json"
之类的请求映射到
@GetMapping("/projects/spring-boot")
:
spring.mvc.contentnegotiation.favor-parameter=true
# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam
# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
如果你了解了注意事项,但仍希望你的应用程序使用后缀模式匹配,则需要以下配置:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
另外,与其打开所有后缀模式,不如只支持已注册的后缀模式,这更安全:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc
ConfigurableWebBindingInitializer
Spring MVC使用 WebBindingInitializer
来为特定请求初始化 WebDataBinder
。
如果创建自己的 ConfigurableWebBindingInitializer
@Bean
,Spring Boot会自动配置Spring MVC以使用它。
模板引擎
除了REST Web服务之外,你还可以使用Spring MVC来提供动态HTML内容。Spring MVC支持各种模板技术, 包括Thymeleaf,FreeMarker和JSP。同样,许多其他模板引擎也提供包括他们自己的Spring MVC集成。
Spring Boot包含对以下模板引擎的自动配置支持:
如果可能,应避免使用JSP。将它们与嵌入式servlet容器一起使用时,存在几个已知的限制。 |
当你使用默认配置的这些模板引擎之一时,将从 src/main/resources/templates
中自动提取模板。
根据你运行应用程序的方式,IntelliJ IDEA对类路径的排序不同。与使用Maven或Gradle或从其打包的jar运行应用程序时相比,
从IDE的main方法运行应用程序的顺序会有所不同。这可能导致Spring Boot无法在类路径上找到模板。
如果遇到此问题,可以在IDE中重新排序类路径,以首先放置模块的类和资源。
或者,你可以配置模板前缀以搜索类路径上的每个 templates 目录,例如:classpath*:/templates/ 。
|
错误处理
默认情况下,Spring Boot提供一个 /error
映射,以一种明智的方式处理所有错误,并且在servlet容器中注册为“global
”错误页面。
对于机器客户端,它将生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
对于浏览器客户端,有一个“whitelabel
”错误视图以HTML格式呈现相同的数据(要对其进行自定义,请添加一个可解决 error
的 View
)。
要完全替换默认行为,可以实现 ErrorController
并注册该类型的bean定义,或者添加类型为 ErrorAttributes
的bean以使用现有机制,但替换其内容。
BasicErrorController 可用作自定义 ErrorController 的基类。如果要为新的内容类型添加处理程序(默认是专门处理
text/html 并为其他所有内容提供降级功能),则此功能特别有用。为此,请继承 BasicErrorController ,添加具有 @RequestMapping
的公共方法,该方法具有 produces 属性,并创建新类型的Bean。
|
你还可以定义一个用 @ControllerAdvice
注解的类,以自定义JSON文档以针对特定的控制器和/或异常类型返回,如以下示例所示:
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
在前面的示例中,如果与 AcmeController
在同一包中定义的控制器抛出 YourException
,则使用 CustomErrorType
POJO的JSON表示形式而不是 ErrorAttributes
表示形式。
自定义错误页面
如果要显示给定状态码的自定义HTML错误页面,可以将文件添加到 /error
文件夹。
错误页面可以是静态HTML(即添加到任何静态资源文件夹下),也可以使用模板来构建。文件名应为确切的状态码或系列掩码。
例如,要将 404
映射到静态HTML文件,你的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用FreeMarker模板映射所有 5xx
错误,你的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftlh
+- <other templates>
对于更复杂的映射,还可以添加实现 ErrorViewResolver
接口的bean,如以下示例所示:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}
}
你还可以使用常规的Spring MVC功能,例如: @ExceptionHandler
方法和
@ControllerAdvice
。然后,ErrorController
拾取所有未处理的异常。
在Spring MVC之外映射错误页面
对于不使用Spring MVC的应用程序,可以使用 ErrorPageRegistrar
接口直接注册 ErrorPages
。
此抽象直接与基础嵌入式servlet容器一起使用,即使你没有Spring MVC DispatcherServlet
它也可以使用。
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}
// ...
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
如果你在 ErrorPage 上注册了一个最终由 Filter 处理的路径(这在某些非Spring Web框架中很常见,如Jersey和Wicket),
则必须将 Filter 显式注册为 ERROR 调度程序,如下面的例子所示:
|
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
请注意,默认的 FilterRegistrationBean
不包含 ERROR
调度程序类型。
当部署到Servlet容器时,Spring Boot使用其错误页面过滤器将具有错误状态的请求转发到适当的错误页面。
如果尚未提交响应,则只能将请求转发到正确的错误页面。缺省情况下,WebSphere Application Server 8.0
及更高版本在成功完成servlet的服务方法后提交响应。
你应该通过将 com.ibm.ws.webcontainer.invokeFlushAfterService 设置为 false 来禁用此行为。
|
Spring HATEOAS
如果你开发使用超媒体的RESTful API,Spring Boot将为Spring HATEOAS提供自动配置,
该配置可与大多数应用程序很好地兼容。自动配置取代了手动使用 @EnableHypermediaSupport
的需要,
并注册了许多bean来简化基于超媒体的应用程序的构建,其中包括 LinkDiscoverers
(用于客户端支持)和 ObjectMapper
其配置为将响应正确地组装为所需的表示形式。通过设置各种 spring.jackson.*
属性,
或通过 Jackson2ObjectMapperBuilder
bean(如果存在)来定制 ObjectMapper
。
你可以使用 @EnableHypermediaSupport
来控制Spring HATEOAS的配置。请注意,这样做会禁用前面所述的 ObjectMapper
定制。
CORS支持
从4.2版本开始,Spring MVC 支持CORS。在Spring Boot应用程序中使用带有
@CrossOrigin
注解的 控制器方法CORS配置不需要任何特定的配置。
可以通过使用自定义的 addCorsMappings(CorsRegistry)
方法注册 WebMvcConfigurer
Bean来定义
全局CORS配置,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}
2.7.2. Spring WebFlux框架
Spring WebFlux是Spring Framework 5.0中引入的新响应式Web框架。 与Spring MVC不同,它不需要Servlet API,是完全异步和非阻塞的,并且通过 Reactor项目 实现 Reactive Streams规范。
Spring WebFlux有两种形式:函数式的和基于注解的。基于注解的模型非常类似于Spring MVC模型,如以下示例所示:
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
}
函数式变体“WebFlux.fn
”将路由配置与请求的实际处理分开,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}
WebFlux是Spring Framework的一部分,其 参考文档中提供了详细信息。
你可以根据需要定义任意数量的 RouterFunction beans,以对路由器的定义进行模块化。如果需要应用优先级,可以排序Beans。
|
首先将 spring-boot-starter-webflux
模块添加到你的应用程序。
在应用程序中同时添加 spring-boot-starter-web 和 spring-boot-starter-webflux 模块会导致Spring
Boot自动配置Spring MVC,而不是WebFlux。之所以选择这种行为,是因为许多Spring开发人员将 spring-boot-starter-webflux
添加到其Spring MVC应用程序中以使用响应式 WebClient 。你仍然可以通过将选定的应用程序类型设置为
SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) 来强制执行选择。
|
Spring WebFlux自动配置
Spring Boot为Spring WebFlux提供了自动配置,可与大多数应用程序很好地配合使用。
自动配置在Spring的默认设置之上添加了以下功能:
如果你想保留Spring Boot WebFlux功能并想要添加其他WebFlux配置,则可以添加自己的类型为
WebFluxConfigurer
的 @Configuration
类,但 不 添加 @EnableWebFlux
。
如果要完全控制Spring WebFlux,则可以添加带有 @EnableWebFlux
注解的自己的 @Configuration
。
带有HttpMessageReaders和HttpMessageWriters的HTTP编解码器
Spring WebFlux使用 HttpMessageReader
和 HttpMessageWriter
接口转换HTTP请求和响应。
通过查看类路径中可用的库,使用 CodecConfigurer
将它们配置为具有合理的默认值。
Spring Boot为编解码器 spring.codec.*
提供了专用的配置属性。它还通过使用 CodecCustomizer
实例应用进一步的自定义。
例如,将 spring.jackson.*
配置keys应用于Jackson编解码器。
如果需要添加或自定义编解码器,则可以创建一个自定义 CodecCustomizer
组件,如以下示例所示:
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
};
}
}
你还可以利用Boot’s自定义JSON序列化器和反序列化器。
静态内容
默认情况下,Spring Boot从类路径中名为 /static
(或 /public
或 /resources
或 /META-INF/resources
)的目录中提供静态内容。
它使用Spring WebFlux中的 ResourceWebHandler
,以便你可以通过添加自己的 WebFluxConfigurer
并覆盖 addResourceHandlers
方法来修改该行为。
默认情况下,资源映射在 /**
上,但是你可以通过设置 spring.webflux.static-path-pattern
属性来对其进行调整。
例如:将所有资源重定位到 /resources/**
可以实现如下:
spring.webflux.static-path-pattern=/resources/**
你还可以使用 spring.resources.static-locations
自定义静态资源位置。这样做会将默认值替换为目录位置列表。
如果这样做,默认的欢迎页面检测将切换到你的自定义位置。因此,如果启动时你指定的任何位置有 index.html
,则它是应用程序的主页。
除了前面列出的“标准”静态资源位置外,https://www.webjars.org/[Webjar内容]有个特殊情况。如果jar文件以Webjars格式打包,
则从jar文件提供带有 /webjars/**
路径的所有资源。
Spring WebFlux应用程序不严格依赖Servlet API,因此不能将它们部署为war文件,也不使用 src/main/webapp 目录。
|
模板引擎
除了REST Web服务之外,你还可以使用Spring WebFlux来提供动态HTML内容。 Spring WebFlux支持各种模板技术,包括Thymeleaf,FreeMarker和Mustache。
Spring Boot包含对以下模板引擎的自动配置支持:
当你使用默认配置的这些模板引擎之一时,将从 src/main/resources/templates
中自动提取模板。
错误处理
Spring Boot提供了一个 WebExceptionHandler
,以一种明智的方式处理所有错误。它在处理顺序中的位置紧靠WebFlux提供的处理程序之前,
后者被认为是最后一个处理程序。对于机器客户端,它将生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
对于浏览器客户端,有一个“whitelabel”错误处理程序,以HTML格式呈现相同的数据。你还可以提供自己的HTML模板来显示错误(请参阅
下一节)。
定制此功能的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,你可以添加类型为 ErrorAttributes
的bean。
要更改错误处理行为,可以实现 ErrorWebExceptionHandler
并注册该类型的bean定义。由于 WebExceptionHandler
的级别很低,
因此Spring Boot还提供了一个方便的 AbstractErrorWebExceptionHandler
,可让你以WebFlux函数式方式处理错误,如以下示例所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
为了获得更完整的图像,你还可以直接将 DefaultErrorWebExceptionHandler
子类化并重写特定方法。
自定义错误页面
如果要显示给定状态码的自定义HTML错误页面,可以将文件添加到 /error
文件夹。
错误页面可以是静态HTML(即添加到任何静态资源文件夹下),也可以使用模板构建。文件名应为确切的状态码或系列掩码。
例如,要将 404
映射到静态HTML文件,你的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用Mustache模板映射所有 5xx
错误,你的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
Web过滤器
Spring WebFlux提供了一个 WebFilter
接口,可以实现该接口来过滤HTTP请求-响应交换。
在应用程序上下文中找到的 WebFilter
bean将自动用于过滤每个交换。
如果过滤器的顺序很重要,则可以实现 Ordered
或使用 @Order
进行注解。
Spring Boot自动配置会为你配置Web过滤器。这样做时,将使用下表中显示的顺序:
Web过滤器 | 顺序 |
---|---|
|
|
|
|
|
|
2.7.3. JAX-RS和Jersey
如果你更喜欢REST端点的JAX-RS编程模型,则可以使用可用的实现之一来代替Spring MVC。
Jersey 和 Apache CXF开箱即用。
CXF要求你在应用程序上下文中将其 Servlet
或 Filter
注册为 @Bean
。
Jersey提供了一些native Spring支持,因此我们还在Spring Boot中提供了对它的自动配置支持,以及一个启动器。
要开始使用Jersey,请将 spring-boot-starter-jersey
作为依赖项包括在内,然后需要一个
ResourceConfig
类型的 @Bean
,在其中注册所有端点,如以下示例所示:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
}
Jersey’s对扫描可执行档案的支持非常有限。例如:在运行可执行的war文件时,
它无法扫描在完全可执行的jar文件或
WEB-INF/classes 中找到的包中的端点。为了避免这种限制,不应该使用 packages 方法,
而应该使用 register 方法分别注册端点,如前面的示例所示。
|
对于更高级的定制,你还可以注册任意数量的 ResourceConfigCustomizer
实现beans。
所有注册的端点应为具有HTTP资源注解的 @Components
(@GET
和其他注解),如以下示例所示:
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
}
由于端点是Spring @Component
,因此其生命周期由Spring管理,你可以使用 @Autowired
注解注入依赖项,
并使用 @Value
注解注入外部配置。默认情况下,Jersey servlet被注册并映射到 /*
。
你可以通过将 @ApplicationPath
添加到 ResourceConfig
来更改映射。
默认情况下,Jersey在名为 jerseyServletRegistration
的 ServletRegistrationBean
类型的 @Bean
中设置为Servlet。
默认情况下,该Servlet延迟初始化,但是你可以通过设置 spring.jersey.servlet.load-on-startup
来自定义该行为。
你可以通过创建自己的同名bean之一来禁用或覆盖该bean。你还可以通过设置 spring.jersey.type=filter
(在这种情况下,要替换或覆盖的 @Bean
是 jerseyFilterRegistration
)来使用过滤器而不是servlet。
过滤器具有 @Order
,你可以使用 spring.jersey.filter.order
进行设置。可以通过使用 spring.jersey.init.*
来指定属性映射,
从而为servlet和过滤器注册都赋予init参数。
2.7.4. 嵌入式Servlet容器支持
Servlets, Filters和listeners
使用嵌入式Servlet容器时,可以通过使用Spring beans或扫描Servlet组件来注册Servlet规范中的servlets,过滤器和所有监听器(例如:HttpSessionListener
)。
将Servlets, Filters和Listeners注册为Spring Beans
任何作为Spring Bean的 Servlet
,Filter
或 *Listener
实例都向嵌入式容器注册。如果要在配置过程中引用
application.properties
中的值,这可能特别方便。
默认情况下,如果上下文仅包含单个Servlet,则将其映射到 /
。对于多个servlet bean,bean名称被用作路径前缀。
过滤器映射到 /*
。
如果基于约定的映射不够灵活,则可以使用 ServletRegistrationBean
,FilterRegistrationBean
和 ServletListenerRegistrationBean
类进行完全控制。
通常可以使无序的过滤器beans处于安全状态。如果需要特定的顺序,则应使用 @Order
注解 Filter
或使其实现 Ordered
。
你不能通过使用 @Order
注解 Filter
的bean方法来配置 Filter
的顺序。如果你不能更改 Filter
类以添加 @Order
或实现 Ordered
,
则必须为 Filter
定义一个 FilterRegistrationBean
并使用 setOrder(int)
方法设置注册bean的顺序。
避免配置一个在 Ordered.HIGHEST_PRECEDENCE
上读取请求正文的过滤器,因为它可能与应用程序的字符编码配置不符。
如果Servlet过滤器包装了请求,则应使用小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的顺序来配置它。
要查看应用程序中每个 Filter 的顺序,请为 web 日志记录组
(logging.level.web=debug )启用调试级别的日志记录。然后,将在启动时记录已注册过滤器的详细信息,包括其顺序和URL模式。
|
注册 Filter beans时要小心,因为它们是在应用程序生命周期中很早就初始化的。如果需要注册与其他bean交互的 Filter
,请考虑改用 DelegatingFilterProxyRegistrationBean 。
|
Servlet上下文初始化
嵌入式Servlet容器不会直接执行Servlet 3.0+ javax.servlet.ServletContainerInitializer
接口或Spring的
org.springframework.web.WebApplicationInitializer
接口。这是一个有意的设计决定,
旨在降低在war中运行的第三方库可能破坏Spring Boot应用程序的风险。
如果你需要在Spring Boot应用程序中执行Servlet上下文初始化,则应该注册一个实现
org.springframework.boot.web.servlet.ServletContextInitializer
接口的bean。
单个 onStartup
方法提供对 ServletContext
的访问,并且在必要时可以轻松地用作现有 WebApplicationInitializer
的适配器。
扫描Servlets, Filters和Listeners
使用嵌入式容器时,可以使用 @ServletComponentScan
启用自动注册带有 @WebServlet
,@WebFilter
和 @WebListener
的类。
@ServletComponentScan 在独立容器中无效,而是使用容器的内置发现机制。
|
ServletWebServerApplicationContext
在后台,Spring Boot使用另一种类型的 ApplicationContext
来支持嵌入式Servlet容器。
ServletWebServerApplicationContext
是 WebApplicationContext
的一种特殊类型,
它通过搜索单个 ServletWebServerFactory
bean来自我引导。通常,已经自动配置了
TomcatServletWebServerFactory
,JettyServletWebServerFactory
或 UndertowServletWebServerFactory
。
通常,你不需要了解这些实现类。大多数应用程序都是自动配置的,并且代表你创建了相应的 ApplicationContext
和 ServletWebServerFactory 。
|
自定义嵌入式Servlet容器
可以使用Spring Environment
属性来配置常见的servlet容器设置。通常,你将在 application.properties
文件中定义属性。
常用服务器设置包括:
Spring Boot尝试尽可能多地公开通用设置,但这并不总是可能的。对于这些情况,
专用名称空间提供特定服务器的自定义项(请参阅 server.tomcat
和 server.undertow
)。
例如:可以使用嵌入式servlet容器的特定功能配置 访问日志。
有关完整列表,请参见 ServerProperties 类。
|
编程定制
如果需要以编程方式配置嵌入式Servlet容器,则可以注册一个实现 WebServerFactoryCustomizer
接口的Spring
Bean。WebServerFactoryCustomizer
提供对 ConfigurableServletWebServerFactory
的访问,其中包括许多自定义设置方法。以下示例显示以编程方式设置端口:
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
TomcatServletWebServerFactory ,JettyServletWebServerFactory 和 UndertowServletWebServerFactory 是
ConfigurableServletWebServerFactory 的专用变体,分别具有针对Tomcat,Jetty和Undertow的其他自定义设置方法。
|
直接自定义ConfigurableServletWebServerFactory
如果上述定制技术太有限,则可以自己注册 TomcatServletWebServerFactory
,JettyServletWebServerFactory
或 UndertowServletWebServerFactory
bean。
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}
提供了许多配置选项的设置器。如果你需要做一些更奇特的操作,还提供了几种受保护的方法“hooks
”。有关详细信息,请参见
源代码文档。
2.7.5. 响应式嵌入服务器支持
Spring Boot包含对以下响应式Web嵌入服务器的支持:Reactor Netty,Tomcat,Jetty和Undertow。 大多数开发人员使用适当的“Starter”来获取完全配置的实例。默认情况下,嵌入式服务器在端口8080上侦听HTTP请求。
2.7.6. 响应式服务器资源配置
当自动配置Reactor Netty或Jetty服务器时,Spring Boot将创建特定的bean,这些bean将向服务器实例提供HTTP资源:
ReactorResourceFactory
或 JettyResourceFactory
。
默认情况下,这些资源还将与Reactor Netty和Jetty客户端共享,以实现最佳性能,前提是:
-
服务器和客户端使用相同的技术
-
客户端实例是使用Spring Boot自动配置的
WebClient.Builder
bean构建的
通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean,开发人员可以覆盖Jetty和Reactor
Netty的资源配置 — 这将同时应用于客户端和服务器。
你可以在WebClient Runtime部分中了解有关客户端资源配置的更多信息。
2.8. RSocket
RSocket是用于字节流传输的二进制协议。它通过在单个连接上传递异步消息来支持对称交互模型。
Spring框架的 spring-messaging
模块在客户端和服务器端都支持RSocket请求者和响应者。有关更多详细信息,请参见Spring
Framework参考中的 RSocket部分,其中包括RSocket协议的概述。
2.8.1. RSocket策略自动配置
Spring Boot自动配置一个 RSocketStrategies
bean,该bean提供了编码和解码RSocket有效载荷所需的所有基础设施。
默认情况下,自动配置将尝试(按顺序)配置以下内容:
-
Jackson的 CBOR编解码器
-
Jackson的JSON编解码器
spring-boot-starter-socket
启动器提供了两个依赖项。查阅Jackson支持部分,
了解更多定制的可能性。
开发人员可以通过创建实现 RSocketStrategiesCustomizer
接口的bean来自定义 RSocketStrategies
组件。
请注意,它们的 @Order
很重要,因为它确定编解码器的顺序。
2.8.2. RSocket服务器自动配置
Spring Boot提供了RSocket服务器自动配置。所需的依赖关系由 spring-boot-starter-rsocket
提供。
Spring Boot允许从WebFlux服务器通过WebSocket公开RSocket,或支持独立的RSocket服务器。这取决于应用程序的类型及其配置。
对于WebFlux应用程序(即 WebApplicationType.REACTIVE
类型),RSocket服务器只有在下列属性匹配时才会被插入到Web服务器:
spring.rsocket.server.mapping-path=/rsocket # a mapping path is defined
spring.rsocket.server.transport=websocket # websocket is chosen as a transport
#spring.rsocket.server.port= # no port is defined
只有Reactor Netty才支持将RSocket插入web服务器,因为RSocket本身就是用这个库构建的。 |
另外,RSocket TCP或Websocket服务器也可以作为独立的嵌入式服务器启动。除了依赖性要求之外,唯一需要的配置是为该服务器定义端口:
spring.rsocket.server.port=9898 # the only required configuration
spring.rsocket.server.transport=tcp # you're free to configure other properties
2.8.3. Spring Messaging RSocket支持
Spring Boot将为RSocket自动配置Spring Messaging基础设施。
这意味着Spring Boot将创建一个 RSocketMessageHandler
bean,该bean将处理对你的应用程序的RSocket请求。
2.8.4. 使用 RSocketRequester
调用RSocket服务
在服务器和客户端之间建立RSocket通道后,任何一方都可以向另一方发送或接收请求。
作为服务器,你可以在RSocket @Controller
的任何处理程序方法上注入 RSocketRequester
实例。
作为客户端,你需要首先配置和建立RSocket连接。在这种情况下,Spring Boot会使用预期的编解码器自动配置 RSocketRequester.Builder
。
RSocketRequester.Builder
实例是一个原型bean,这意味着每个注入点将为你提供一个新实例。
这样做是有目的的,因为此构建器是有状态的,因此你不应使用同一实例创建具有不同设置的请求者。
以下代码显示了一个典型示例:
@Service
public class MyService {
private final RSocketRequester rsocketRequester;
public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
this.rsocketRequester = rsocketRequesterBuilder
.connectTcp("example.org", 9898).block();
}
public Mono<User> someRSocketCall(String name) {
return this.requester.route("user").data(name)
.retrieveMono(User.class);
}
}
2.9. 安全
如果 Spring Security在类路径上,则默认情况下Web应用程序是安全的。
Spring Boot依靠Spring Security的内容协商策略来确定是使用 httpBasic
还是 formLogin
。
要将方法级安全性添加到Web应用程序,还可以使用所需的设置添加 @EnableGlobalMethodSecurity
。
可以在 Spring Security参考指南中找到更多信息。
默认的 UserDetailsService
具有单个用户。用户名是 user
,密码是随机的,并在应用程序启动时以INFO级别显示,如下例所示:
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
如果你微调日志记录配置,请确保将 org.springframework.boot.autoconfigure.security 类别设置为记录 INFO
级别的消息。否则,不会打印默认密码。
|
你可以通过提供 spring.security.user.name
和 spring.security.user.password
来更改用户名和密码。
默认情况下,你在Web应用程序中获得的基本功能是:
-
一个具有内存存储的
UserDetailsService
(如果是WebFlux应用程序,则为ReactiveUserDetailsService
)Bean, 一个具有已生成密码的用户(请参阅SecurityProperties.User
以获取用户属性)。 -
整个应用程序的基于表单的登录或HTTP基本安全性(取决于请求中的
Accept
头部)(包括执行器端点,如果执行器位于类路径上)。 -
用于发布身份验证事件的
DefaultAuthenticationEventPublisher
。
你可以通过为它添加一个bean来提供一个不同的 AuthenticationEventPublisher
。
2.9.1. MVC安全
默认的安全配置在 SecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现。
SecurityAutoConfiguration
导入用于Web安全的 SpringBootWebSecurityConfiguration
,
而 UserDetailsServiceAutoConfiguration
配置身份验证,这也与非Web应用程序相关。
要完全关闭默认的Web应用程序安全性配置或合并多个Spring Security组件(例如:OAuth 2客户端和资源服务器),
请添加类型为 WebSecurityConfigurerAdapter
的bean(这样做不会禁用 UserDetailsService
配置或Actuator的安全性)。
要关闭 UserDetailsService
配置,你可以添加
UserDetailsService
、AuthenticationProvider
或 AuthenticationManager
类型的bean。
通过添加自定义 WebSecurityConfigurerAdapter
可以覆盖访问规则。
Spring Boot提供了便捷的方法,可用于覆盖actuator端点和静态资源的访问规则。
EndpointRequest
可用于创建基于 management.endpoints.web.base-path
属性的 RequestMatcher
。
可以使用 PathRequest
为常用位置的资源创建一个 RequestMatcher
。
2.9.2. WebFlux安全
与Spring MVC应用程序类似,你可以通过添加 spring-boot-starter-security
依赖项来保护WebFlux应用程序。
默认的安全配置在 ReactiveSecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现。
ReactiveSecurityAutoConfiguration
导入 WebFluxSecurityConfiguration
以获得Web安全,
而 UserDetailsServiceAutoConfiguration
配置身份验证,这也与非Web应用程序相关。
要完全关闭默认的Web应用程序安全配置,你可以添加 WebFilterChainProxy
类型的Bean
(这样做不会禁用 UserDetailsService
配置或Actuator的安全性)。
要关闭 UserDetailsService
配置,你可以添加类型为 ReactiveUserDetailsService
或 ReactiveAuthenticationManager
的bean。
可以通过添加自定义 SecurityWebFilterChain
bean来配置访问规则以及使用多个Spring Security组件
(例如:OAuth 2 Client和Resource Server)。Spring Boot提供了便捷的方法,可用于覆盖actuator端点和静态资源的访问规则。
EndpointRequest
可用于创建基于 management.endpoints.web.base-path
属性的 ServerWebExchangeMatcher
。
可以使用 PathRequest
为常用位置的资源创建 ServerWebExchangeMatcher
。
例如,你可以通过添加以下内容来自定义安全配置:
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.pathMatchers("/foo", "/bar")
.authenticated().and()
.formLogin().and()
.build();
}
2.9.3. OAuth2
OAuth2是Spring支持的一种广泛使用的授权框架。
客户端
如果你在类路径中具有 spring-security-oauth2-client
,则可以利用一些自动配置功能来轻松设置OAuth2/OpenID Connect客户端。
此配置使用 OAuth2ClientProperties
下的属性。相同的属性适用于servlet和响应式应用程序。
你可以在 spring.security.oauth2.client
前缀下注册多个OAuth2客户端和Provider,如以下示例所示:
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
对于支持 OpenID Connect发现的OpenID
Connect Providers,可以进一步简化配置。
供应商需要配置一个 issuer-uri
,该URI是其声明的Issuer标识符。
例如,如果提供的 issuer-uri
是“https://example.com”,则将向“https://example.com/.well-known/openid-configuration”
发出 OpenID Provider Configuration Request
。结果应为 OpenID Provider Configuration Response
。
以下示例显示了如何使用 issuer-uri
配置OpenID Connect Provider:
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
默认情况下,Spring Security的 OAuth2LoginAuthenticationFilter
仅处理与 /login/oauth2/code/*
匹配的URL。
如果要自定义 redirect-uri
以使用其他模式,则需要提供配置以处理该自定义模式。
例如,对于servlet应用程序,你可以添加自己的类似于以下内容的 WebSecurityConfigurerAdapter
:
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
}
}
常见供应商的OAuth2客户端注册
对于常见的OAuth2和OpenID供应商,包括Google,Github,Facebook和Okta,我们提供了一组供应商默认值(分别为
google
,github
,facebook
和 okta
)。
如果不需要自定义这些供应商,则可以将 provider
属性设置为需要为其推断默认值的属性。
另外,如果用于客户端注册的key与默认支持的供应商匹配,则Spring Boot也会进行推断。
换句话说,以下示例中的两个配置都使用Google供应商:
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
资源服务器
如果你的类路径上有 spring-security-oauth2-resource-server
,则Spring Boot可以设置OAuth2资源服务器。
对于JWT配置,需要指定JWK Set URI或OIDC Issuer URI,如以下示例所示:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
如果授权服务器不支持JWK Set URI,则可以使用用于验证JWT签名的公钥来配置资源服务器。
可以使用 spring.security.oauth2.resourceserver.jwt.public-key-location 属性来完成此操作,
该属性值需要指向包含PEM-encoded x509格式的公钥的文件。
|
相同的属性适用于servlet和响应式应用程序。
另外,你可以为Servlet应用程序定义自己的 JwtDecoder
Bean,或者为响应式应用程序定义 ReactiveJwtDecoder
。
如果使用opaque tokens而不是JWT,则可以配置以下属性以通过自省来验证tokens:
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
同样,相同的属性适用于servlet和响应式应用程序。
另外,你可以为Servlet应用程序定义自己的 OpaqueTokenIntrospector
Bean,或者为响应式应用程序定义
ReactiveOpaqueTokenIntrospector
。
授权服务器
当前,Spring Security不提供对实现OAuth 2.0授权服务器的支持。但是, Spring Security OAuth项目提供了此功能,
最终将被Spring Security完全取代。在此之前,你可以使用 spring-security-oauth2-autoconfigure
模块轻松设置OAuth 2.0授权服务器;有关说明,请参见其 文档。
2.9.4. SAML 2.0
依赖方
如果你在类路径中具有 spring-security-saml2-service-provider
,则可以利用一些自动配置功能来轻松设置
SAML 2.0依赖方。此配置使用 Saml2RelyingPartyProperties
下的属性。
依赖方注册代表身份供应商IDP和服务供应商SP之间的配对配置。你可以在 spring.security.saml2.relyingparty
前缀下注册多个依赖方,如以下示例所示:
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.verification.credentials[0].certificate-location=path-to-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.entity-id=remote-idp-entity-id1
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.sso-url=https://remoteidp1.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.verification.credentials[0].certificate-location=path-to-other-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.entity-id=remote-idp-entity-id2
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.sso-url=https://remoteidp2.sso.url
2.9.5. Actuator安全
为了安全起见,默认情况下禁用 /health
和 /info
以外的所有actuators。
management.endpoints.web.exposure.include
属性可用于启用actuators。
如果Spring Security位于类路径上,并且不存在其他 WebSecurityConfigurerAdapter
,
则除 /health
和 /info
以外的所有actuators均由Spring Boot自动配置保护。
如果定义自定义 WebSecurityConfigurerAdapter
,则Spring Boot自动配置将退出,你将完全控制actuator访问规则。
在设置 management.endpoints.web.exposure.include 之前,请确保暴露的actuators不包含敏感信息和/或通过将它们放置在防火墙后面或通过诸如
Spring Security之类的方法进行保护。
|
跨站请求伪造保护
由于Spring Boot依赖于Spring Security的默认设置,因此CSRF保护默认情况下处于启用状态。 这意味着在使用默认安全配置时,需要POST(shutdown和loggers端点),PUT或DELETE的actuator端点将收到403 forbidden错误。
我们建议仅在创建非浏览器客户端使用的服务时完全禁用CSRF保护。 |
关于CSRF保护的其他信息可以在 Spring Security参考指南中找到。
2.10. 使用SQL数据库
Spring Framework为使用SQL数据库提供了广泛的支持,从使用 JdbcTemplate
的直接JDBC
访问到完整的“对象关系映射
”技术(例如:Hibernate)。
Spring Data提供了更高级别的功能:直接从接口创建 Repository
实现,并使用约定从你的方法名称生成查询。
2.10.1. 配置DataSource
Java的 javax.sql.DataSource
接口提供了使用数据库连接的标准方法。传统上,“DataSource”使用 URL
和一些凭据来建立数据库连接。
有关更多高级示例,请参见 "How-to"部分,通常可以完全控制DataSource的配置。 |
嵌入式数据库支持
使用内存嵌入式数据库来开发应用程序通常很方便。显然,内存数据库不提供持久存储。你需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。
"How-to"部分包括有关 如何初始化数据库的部分。 |
如果你在测试中使用此功能,则可能会注意到,整个测试套件将重复使用同一数据库,而不管你使用的应用程序上下文有多少。
如果要确保每个上下文都有一个单独的嵌入式数据库,则应将 |
例如,典型的POM依赖关系如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
你需要依赖 spring-jdbc 来自动配置嵌入式数据库。在此示例中,它通过 spring-boot-starter-data-jpa 传递性地传入。
|
如果出于某种原因确实为嵌入式数据库配置了连接URL,请务必确保禁用了数据库的自动关闭功能。
如果使用H2,则应使用 DB_CLOSE_ON_EXIT=FALSE 进行操作。如果使用HSQLDB,则应确保未使用 shutdown=true 。
通过禁用数据库的自动关闭功能,Spring Boot可以控制何时关闭数据库,从而确保一旦不再需要访问数据库时就可以进行自动关闭。
|
连接到生产数据库
生产数据库连接也可以通过使用池化 DataSource
来自动配置。Spring Boot使用以下算法来选择特定的实现:
-
我们更喜欢 HikariCP的性能和并发性。如果有HikariCP,我们总是选择它。
-
反之,如果Tomcat池化
DataSource
可用,我们将使用它。 -
HikariCP和Tomcat池数据源均不可用,如果 Commons DBCP2可用,我们将使用它。
如果你使用 spring-boot-starter-jdbc
或 spring-boot-starter-data-jpa
“starters
”,则会自动获得对
HikariCP
的依赖。
你可以通过设置 spring.datasource.type 属性来完全绕过该算法,并指定要使用的连接池。
如果你在Tomcat容器中运行应用程序,这一点尤其重要,因为默认情况下提供了 tomcat-jdbc 。
|
其他连接池始终可以手动配置。如果定义自己的 DataSource bean,则不会进行自动配置。
|
DataSource配置由 spring.datasource.*
中的外部配置属性控制。例如:你可以在 application.properties
中声明以下部分:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
你至少应通过设置 spring.datasource.url 属性来指定URL。否则,Spring Boot会尝试自动配置嵌入式数据库。
|
你通常不需要指定 driver-class-name 名称,因为Spring Boot可以根据 url 从大多数数据库推断出它。
|
对于要创建池化 DataSource ,我们需要能够验证有效的 Driver 类是否可用,因此我们在进行任何操作之前都要进行检查。
换句话说,如果设置 spring.datasource.driver-class-name=com.mysql.jdbc.Driver ,则该类必须是可加载的。
|
有关更多受支持的选项,请参见 DataSourceProperties
。
这些是不管实际实现如何都会起作用的标准选项。也可以使用它们各自的前缀(
spring.datasource.hikari.*
, spring.datasource.tomcat.*
和 spring.datasource.dbcp2.*
)
微调实现特定的设置。有关更多详细信息,请参阅所用连接池实现的文档。
例如,如果使用 Tomcat连接池,则可以自定义许多其他设置,如以下示例所示:
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50
# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true
连接到JNDI数据源
如果你将Spring Boot应用程序部署到Application Server,则可能需要使用Application Server的内置功能来配置和管理DataSource,并使用JNDI对其进行访问。
spring.datasource.jndi-name
属性可以用作 spring.datasource.url
,spring.datasource.username
和
spring.datasource.password
属性的替代方案,以从特定的JNDI位置访问 DataSource
。
例如:application.properties
中的以下部分显示了如何访问JBoss AS定义的 DataSource
:
spring.datasource.jndi-name=java:jboss/datasources/customers
2.10.2. 使用JdbcTemplate
Spring的 JdbcTemplate
和 NamedParameterJdbcTemplate
类是自动配置的,你可以将它们直接 @Autowire
到自己的bean中,如以下示例所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JdbcTemplate jdbcTemplate;
@Autowired
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// ...
}
你可以使用 spring.jdbc.template.*
属性来自定义模板的某些属性,如以下示例所示:
spring.jdbc.template.max-rows=500
NamedParameterJdbcTemplate 在幕后重用相同的 JdbcTemplate 实例。如果定义了多个 JdbcTemplate
并且不存在主要候选对象,则不会自动配置 NamedParameterJdbcTemplate 。
|
2.10.3. JPA和Spring Data JPA
Java Persistence API是一种标准技术,可让你将对象“映射”到关系数据库。
spring-boot-starter-data-jpa
POM提供了一种快速入门的方法。它提供以下关键依赖:
-
Hibernate: 最受欢迎的JPA实现之一。
-
Spring Data JPA: 使基于JPA的存储库的实现变得容易。
-
Spring ORMs: Spring框架对ORM的核心支持。
在这里,我们不会过多讨论JPA或 Spring Data。 你可以按照 https://spring.io 的 “使用JPA访问数据”指南进行操作, 并阅读 Spring Data JPA和 Hibernate参考文档。 |
实体类
传统上,JPA“Entity
”类在 persistence.xml
文件中指定。在Spring Boot中,此文件不是必需的,而是使用“实体扫描”。
默认情况下,将搜索主配置类(用 @EnableAutoConfiguration
或 @SpringBootApplication
注解的一个)下的所有软件包。
考虑任何带有 @Entity
,@Embeddable
或 @MappedSuperclass
注解的类。典型的实体类类似于以下示例:
package com.example.myapp.domain;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class City implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
// ... additional members, often include @OneToMany mappings
protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used directly
}
public City(String name, String state) {
this.name = name;
this.state = state;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
// ... etc
}
你可以使用 @EntityScan 注解来自定义实体扫描位置。请参见
“从Spring配置中分离@Entity定义”。
|
Spring Data JPA存储库
Spring Data JPA存储库是可以定义以访问数据的接口。JPA查询是根据你的方法名称自动创建的。
例如:CityRepository
接口可能声明了 findAllByState(String state)
方法来查找给定状态下的所有城市。
对于更复杂的查询,你可以使用Spring Data的 Query
注解对方法进行注释。
Spring Data存储库通常从 Repository
或
CrudRepository
接口继承。
如果使用自动配置,则会从包含主配置类(以 @EnableAutoConfiguration
或 @SpringBootApplication
注解的主配置类)的包中搜索存储库。
以下示例显示了典型的Spring Data存储库接口定义:
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
}
Spring Data JPA存储库支持三种不同的引导模式:default, deferred 和 lazy。
要启用deferred引导或lazy引导,请将 spring.data.jpa.repositories.bootstrap-mode
属性分别设置为 deferred
或 lazy
。
使用deferred或lazy启动时,自动配置的 EntityManagerFactoryBuilder
将使用上下文的 AsyncTaskExecutor
(如果有)作为引导执行器。
如果存在多个,则将使用一个名为 applicationTaskExecutor
的执行器。
我们仅仅触及了Spring Data JPA的皮毛。有关完整的详细信息,请参阅 Spring Data JPA参考文档。 |
创建和删除JPA数据库
默认情况下,仅 当你使用嵌入式数据库(H2,HSQL或Derby)时,才会自动创建JPA数据库。
你可以使用 spring.jpa.*
属性显式配置JPA设置。
例如:要创建和删除表,可以将以下行添加到 application.properties
:
spring.jpa.hibernate.ddl-auto=create-drop
为此,Hibernate自己的内部属性名称是 hibernate.hbm2ddl.auto 。
你可以使用 spring.jpa.properties.* (将它们添加到实体管理器时,会先剔除前缀)来设置它以及其他Hibernate本地属性。
下面的行显示了为Hibernate设置JPA属性的示例:
|
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
前面示例中的行将 hibernate.globally_quoted_identifiers
属性值设置为 true
传递给Hibernate实体管理器。
默认情况下,DDL执行(或验证)推迟到 ApplicationContext
启动之后。还有一个 spring.jpa.generate-ddl
标志,
但是如果Hibernate自动配置处于活动状态,则不会使用它,因为 ddl-auto
设置粒度更细。
在视图中打开EntityManager
如果你正在运行Web应用程序,则Spring Boot默认情况下会注册
OpenEntityManagerInViewInterceptor
以应用“在视图中打开EntityManager”模式,以允许在Web视图中进行延迟加载。
如果你不希望出现这种情况,则应在 application.properties
中将 spring.jpa.open-in-view
设置为 false
。
2.10.4. Spring Data JDBC
Spring Data包括对JDBC的存储库支持,并将为 CrudRepository
上的方法自动生成SQL。对于更高级的查询,提供了 @Query
注解。
当必要的依赖项位于类路径上时,Spring Boot将自动配置Spring Data的JDBC存储库。
可以将它们添加到你的项目中,而只需依赖 spring-boot-starter-data-jdbc
。
如有必要,你可以通过在应用程序中添加 @EnableJdbcRepositories
注解或
JdbcConfiguration
子类来控制Spring Data JDBC的配置。
有关Spring Data JDBC的完整详细信息,请参考 参考文档。 |
2.10.5. 使用H2的Web控制台
-
你正在开发基于servlet的Web应用程序。
-
com.h2database:h2
在类路径上。 -
你正在使用 Spring Boot的开发者工具。
如果你未使用Spring Boot的开发者工具,但仍想使用H2的控制台,则可以将 spring.h2.console.enabled 属性配置为 true 。
|
H2控制台仅在开发期间使用,因此应注意确保在生产中未将 spring.h2.console.enabled 设置为 true 。
|
更改H2控制台的路径
默认情况下,该控制台在 /h2-console
端点可用。你可以使用 spring.h2.console.path
属性来自定义控制台的路径。
2.10.6. 使用jOOQ
jOOQ Object Oriented Querying (jOOQ)是 Data Geekery 的一种流行产品,它可以从数据库中生成Java代码,并允许你通过其流式API构建类型安全的SQL查询。商业版和开源版都可以与Spring Boot一起使用。
代码生成
为了使用jOOQ类型安全查询,你需要从数据库schema中生成Java类。你可以按照 jOOQ用户手册中的说明进行操作。
如果你使用 jooq-codegen-maven
插件,并且还使用 spring-boot-starter-parent
“父POM”,
则可以安全地忽略该插件的 <version>
标签。你还可以使用Spring Boot定义的版本变量(例如:h2.version
)
来声明插件的数据库依赖关系。以下清单显示了一个示例:
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
...
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
...
</generator>
</configuration>
</plugin>
使用DSLContext
jOOQ提供的流式API是通过 org.jooq.DSLContext
接口启动的。
Spring Boot将 DSLContext
自动配置为Spring Bean,并将其连接到你的应用程序 DataSource
。
要使用 DSLContext
,可以使用 @Autowire
,如下例所示:
@Component
public class JooqExample implements CommandLineRunner {
private final DSLContext create;
@Autowired
public JooqExample(DSLContext dslContext) {
this.create = dslContext;
}
}
jOOQ手册倾向于使用名为 create 的变量来保存 DSLContext 。
|
然后,可以使用 DSLContext
构造查询,如以下示例所示:
public List<GregorianCalendar> authorsBornAfter1980() {
return this.create.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
.fetch(AUTHOR.DATE_OF_BIRTH);
}
jOOQ SQL方言
除非已配置 spring.jooq.sql-dialect
属性,否则Spring Boot会确定要用于数据源的SQL方言。如果Spring Boot无法检测到方言,则使用 DEFAULT
。
Spring Boot只能自动配置开源版本的jOOQ支持的方言。 |
自定义jOOQ
可以通过定义自己的 @Bean
定义来实现更高级的自定义,这在创建jOOQ Configuration
时将使用。你可以为以下jOOQ类型定义bean:
-
ConnectionProvider
-
ExecutorProvider
-
TransactionProvider
-
RecordMapperProvider
-
RecordUnmapperProvider
-
Settings
-
RecordListenerProvider
-
ExecuteListenerProvider
-
VisitListenerProvider
-
TransactionListenerProvider
如果要完全控制jOOQ配置,也可以创建自己的 org.jooq.Configuration
@Bean
。
2.11. 使用NoSQL技术
Spring Data提供了其他项目来帮助你访问各种NoSQL技术,包括:
Spring Boot为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase和LDAP提供自动配置。 你可以使用其他项目,但必须自己进行配置。请参阅 https://spring.io/projects/spring-data 中的相应参考文档。
2.11.1. Redis
有一个 spring-boot-starter-data-redis
“Starter” 便于收集依赖项。默认情况下,它使用
Lettuce。
该启动器可以处理传统应用程序和响应式应用程序。
我们还提供了一个 spring-boot-starter-data-redis-reactive “Starter ”,以与具有响应式支持的其他存储保持一致。
|
连接到Redis
你可以像注入其他任何Spring Bean一样注入自动配置的 RedisConnectionFactory
,StringRedisTemplate
或vanilla
RedisTemplate
实例。默认情况下,该实例尝试连接到位于 localhost:6379
的Redis服务器。
下面的清单显示了这种Bean的示例:
@Component
public class MyBean {
private StringRedisTemplate template;
@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}
// ...
}
你还可以注册任意数量的Bean,这些Bean实现 LettuceClientConfigurationBuilderCustomizer 以获得更高级的自定义。
如果使用Jedis,则可以使用 JedisClientConfigurationBuilderCustomizer 。
|
如果添加自己的任何自动配置类型的 @Bean
,它将替换默认值
(RedisTemplate
除外,除非排除是基于bean名称 redisTemplate
而不是其类型时)。
默认情况下,如果 commons-pool2
在类路径上,则会得到一个池化的连接工厂。
2.11.2. MongoDB
MongoDB是一个开源NoSQL文档数据库,它使用类似JSON的结构而不是传统的基于表的关系数据。
Spring Boot为MongoDB的使用提供了许多便利,包括 spring-boot-starter-data-mongodb
和
spring-boot-starter-data-mongodb-reactive
“Starter”。
连接到MongoDB数据库
要访问Mongo数据库,可以注入自动配置的 org.springframework.data.mongodb.MongoDbFactory
。
默认情况下,该实例尝试通过 mongodb://localhost/test
连接到MongoDB服务器。
以下示例显示了如何连接到MongoDB数据库:
import org.springframework.data.mongodb.MongoDbFactory;
import com.mongodb.DB;
@Component
public class MyBean {
private final MongoDbFactory mongo;
@Autowired
public MyBean(MongoDbFactory mongo) {
this.mongo = mongo;
}
// ...
public void example() {
DB db = mongo.getDb();
// ...
}
}
你可以设置 spring.data.mongodb.uri
属性来更改URL并配置其他设置,例如 副本集,如以下示例所示:
spring.data.mongodb.uri=mongodb://user:secret@mongo1.example.com:12345,mongo2.example.com:23456/test
另外,只要你使用Mongo 2.x,就可以指定 host
/port
。例如:你可以在 application.properties
中声明以下设置:
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
如果你定义了自己的 MongoClient
,它将用于自动配置合适的 MongoDbFactory
。com.mongodb.MongoClient
和
com.mongodb.client.MongoClient
均受支持。
如果使用Mongo 3.0 Java驱动程序,则不支持 spring.data.mongodb.host 和 spring.data.mongodb.port 。
在这种情况下,应使用 spring.data.mongodb.uri 提供所有配置。
|
如果未指定 spring.data.mongodb.port ,则使用默认值 27017 。你可以从前面显示的示例中删除此行。
|
如果不使用Spring Data Mongo,则可以注入 com.mongodb.MongoClient bean,而不是使用 MongoDbFactory 。
如果你想完全控制建立MongoDB连接的方式,还可以声明自己的 MongoDbFactory 或 MongoClient bean。
|
如果你使用响应式驱动程序,则SSL需要Netty。如果Netty可用并且尚未自定义要使用的工厂,则自动配置会自动配置该工厂。 |
MongoTemplate
Spring Data MongoDB提供了一个 MongoTemplate
类,
该类的设计与Spring的 JdbcTemplate
非常相似。与 JdbcTemplate
一样,Spring Boot为你自动配置一个Bean来注入模板,如下所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final MongoTemplate mongoTemplate;
@Autowired
public MyBean(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
// ...
}
有关完整的详细信息,请参见 MongoOperations
Javadoc。
Spring Data MongoDB存储库
Spring Data包括对MongoDB的存储库支持。与前面讨论的JPA存储库一样,基本原理是根据方法名称自动构造查询。
实际上,Spring Data JPA和Spring Data MongoDB共享相同的通用基础设施。你可以从以前的JPA示例开始,并假设 City
现在是Mongo数据类,而不是JPA
@Entity
,它的工作方式相同,如以下示例所示:
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
}
你可以使用 @EntityScan 注解来自定义文档扫描位置。
|
有关Spring Data MongoDB的完整详细信息,包括其丰富的对象映射技术,请参阅其 参考文档。 |
嵌入式Mongo
Spring Boot为 Embedded Mongo提供自动配置。
要在Spring Boot应用程序中使用它,请添加对 de.flapdoodle.embed:de.flapdoodle.embed.mongo
的依赖。
可以通过设置 spring.data.mongodb.port
属性来配置Mongo监听的端口。要使用随机分配的空闲端口,请使用0值。
MongoAutoConfiguration
创建的 MongoClient
将自动配置为使用随机分配的端口。
如果未配置自定义端口,则默认情况下,嵌入式支持会使用随机端口(而不是27017)。 |
如果类路径上有SLF4J,则Mongo产生的输出将自动路由到名为 org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo
的记录器。
你可以声明自己的 IMongodConfig
和 IRuntimeConfig
bean,以控制Mongo实例的配置和日志记录路由。
可以通过声明 DownloadConfigBuilderCustomizer
bean来定制下载配置。
2.11.3. Neo4j
Neo4j是一个开源NoSQL图形数据库,它使用了由一级关系连接的节点的丰富数据模型,
与传统的RDBMS方法相比,它更适合于连接的大数据。Spring Boot为Neo4j的使用提供了许多便利,包括 spring-boot-starter-data-neo4j
“Starter”。
连接到Neo4j数据库
要访问Neo4j服务器,你可以注入自动配置的 org.neo4j.ogm.session.Session
。
默认情况下,该实例尝试使用Bolt协议连接到 localhost:7687
处的Neo4j服务器。下面的示例显示如何注入Neo4j Session
:
@Component
public class MyBean {
private final Session session;
@Autowired
public MyBean(Session session) {
this.session = session;
}
// ...
}
你可以通过设置 spring.data.neo4j.*
属性来配置要使用的uri和凭据,如以下示例所示:
spring.data.neo4j.uri=bolt://my-server:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
通过添加 org.neo4j.ogm.config.Configuration
bean或 org.neo4j.ogm.session.SessionFactory
bean,可以完全控制会话的创建。
使用嵌入式模式
如果将 org.neo4j:neo4j-ogm-embedded-driver
添加到应用程序的依赖项中,
则Spring Boot会自动配置Neo4j的进程内嵌入式实例,该实例在应用程序关闭时不会保留任何数据。
由于嵌入式Neo4j OGM驱动程序本身不提供Neo4j内核,因此你必须自己声明 org.neo4j:neo4j 为依赖项。
有关兼容版本的列表,请参阅 Neo4j OGM文档。
|
当类路径上有多个驱动程序时,嵌入式驱动程序优先于其他驱动程序。你可以通过设置 spring.data.neo4j.embedded.enabled=false
显式禁用嵌入式模式。
如果嵌入式驱动程序和Neo4j内核位于上述类路径上, 则Data Neo4j Tests会自动使用嵌入式Neo4j实例。
你可以通过在配置中提供数据库文件的路径来启用嵌入式模式的持久性。
例如: spring.data.neo4j.uri=file://var/tmp/graph.db 。
|
使用Native类型
Neo4j-OGM可以将某些类型(例如:java.time.*
中的类型)映射到基于String的属性或Neo4j提供的原生类型之一。
出于向后兼容的原因,Neo4j-OGM的默认设置是使用基于字符串的表示形式。要使用原生类型,请添加对
org.neo4j:neo4j-ogm-bolt-native-types
或 org.neo4j:neo4j-ogm-embedded-native-types
的依赖关系,
并配置 spring.data.neo4j.use-native-types
属性,如以下示例所示:
spring.data.neo4j.use-native-types=true
Neo4jSession
默认情况下,如果你正在运行Web应用程序,则会话将绑定到线程以进行请求的整个处理(即,它使用“Open Session in View”模式)。
如果你不希望出现这种情况,请将以下行添加到 application.properties
文件中:
spring.data.neo4j.open-in-view=false
Spring Data Neo4j存储库
Spring Data包括对Neo4j的存储库支持。
Spring Data Neo4j与许多其他Spring Data模块一样,与Spring Data JPA共享公共基础设施。
你可以采用前面的JPA示例,并将 City
定义为Neo4j OGM @NodeEntity
而不是JPA @Entity
,并且存储库抽象以相同的方式工作,如以下示例所示:
package com.example.myapp.domain;
import java.util.Optional;
import org.springframework.data.neo4j.repository.*;
public interface CityRepository extends Neo4jRepository<City, Long> {
Optional<City> findOneByNameAndState(String name, String state);
}
spring-boot-starter-data-neo4j
“Starter” 可支持存储库以及事务管理。
你可以通过分别在 @Configuration
-bean上使用 @EnableNeo4jRepositories
和 @EntityScan
来定制位置以查找存储库和实体。
有关Spring Data Neo4j的完整详细信息,包括其对象映射技术,请参阅 参考文档。 |
2.11.4. Solr
Apache Solr是一个搜索引擎。
Spring Boot为Solr 5客户端库提供了基本的自动配置,并由 Spring Data Solr在其之上提供了抽象。
spring-boot-starter-data-solr
“Starter” 用于以方便的方式收集依赖项。
连接到Solr
你可以像插入其他任何Spring Bean一样注入自动配置的 SolrClient
实例。默认情况下,该实例尝试连接到位于
http://localhost:8983/solr
的服务器。以下示例显示如何注入Solr bean:
@Component
public class MyBean {
private SolrClient solr;
@Autowired
public MyBean(SolrClient solr) {
this.solr = solr;
}
// ...
}
如果添加自己的类型为 SolrClient
的 @Bean
,它将替换默认值。
Spring Data Solr存储库
Spring Data包括对Apache Solr的存储库支持。与前面讨论的JPA存储库一样,基本原理是根据方法名称自动为你构建查询。
实际上,Spring Data JPA和Spring Data Solr共享相同的通用基础设施。你可以从以前的JPA示例开始,并假设 City
现在是
@SolrDocument
类,而不是JPA @Entity
,它的工作方式相同。
有关Spring Data Solr的完整详细信息,请参阅 参考文档。 |
2.11.5. Elasticsearch
Elasticsearch是一个开源,分布式,RESTful搜索和分析引擎。 Spring Boot为Elasticsearch提供了基本的自动配置。
Spring Boot支持多个客户端:
-
官方Java“低级”和“高级”REST客户端
-
Spring Data Elasticsearch提供的
ReactiveElasticsearchClient
传输客户端仍然可用,但是 Spring Data Elasticsearch和Elasticsearch本身已弃用了它的支持。
它将在未来的版本中删除。Spring Boot提供了专用的 “Starter”, 即 spring-boot-starter-data-elasticsearch
。
由于Elasticsearch和Spring Data Elasticsearch为REST客户端提供了官方支持,因此 Jest客户端也已被弃用。
使用REST客户端连接到Elasticsearch
Elasticsearch附带了两个可用于查询集群的 REST客户端: “低级”客户端和“高级”客户端。
如果你的类路径具有 org.elasticsearch.client:elasticsearch-rest-client
依赖关系,Spring Boot将自动配置并注册一个 RestClient
Bean,默认情况下,它连接到 http://localhost:9200
。你可以进一步调整 RestClient
的配置方式,如以下示例所示:
spring.elasticsearch.rest.uris=https://search.example.com:9200
spring.elasticsearch.rest.read-timeout=10s
spring.elasticsearch.rest.username=user
spring.elasticsearch.rest.password=secret
你还可以注册任意数量的Bean,它们实现了 RestClientBuilderCustomizer
来进行更高级的自定义。要完全控制注册,请定义 RestClient
bean。
如果你的类路径具有 org.elasticsearch.client:elasticsearch-rest-high-level-client
依赖关系,
则Spring Boot将自动配置 RestHighLevelClient
,它将包装任何现有的 RestClient
bean,并重用其HTTP配置。
使用响应式REST客户端连接到Elasticsearch
Spring Data Elasticsearch 提供了 ReactiveElasticsearchClient
,用于以响应式方式查询Elasticsearch实例。
它基于WebFlux的 WebClient
构建,因此 spring-boot-starter-elasticsearch
和 spring-boot-starter-webflux
依赖关系对于启用此支持都是有用的。
默认情况下,Spring Boot将自动配置并注册一个针对 http://localhost:9200
的 ReactiveElasticsearchClient
bean。你可以进一步调整其配置,如以下示例所示:
spring.data.elasticsearch.client.reactive.endpoints=search.example.com:9200
spring.data.elasticsearch.client.reactive.use-ssl=true
spring.data.elasticsearch.client.reactive.socket-timeout=10s
spring.data.elasticsearch.client.reactive.username=user
spring.data.elasticsearch.client.reactive.password=secret
如果配置属性不够,并且你想完全控制客户端配置,则可以注册自定义 ClientConfiguration
bean。
使用Jest连接到Elasticsearch
现在,Spring Boot支持官方的 RestHighLevelClient
,不再支持Jest。
如果在类路径上有 Jest
,则可以注入默认情况下以 http://localhost:9200
为目标的自动配置的 JestClient
。
你可以进一步调整客户端的配置,如以下示例所示:
spring.elasticsearch.jest.uris=https://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret
你还可以注册任意数量的实现 HttpClientConfigBuilderCustomizer
的bean,以进行更高级的自定义。以下示例调整其他HTTP设置:
static class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {
@Override
public void customize(HttpClientConfig.Builder builder) {
builder.maxTotalConnection(100).defaultMaxTotalConnectionPerRoute(5);
}
}
要完全控制注册,请定义 JestClient
bean。
使用Spring Data连接到Elasticsearch
要连接到Elasticsearch,必须定义由Spring Boot自动配置或由应用程序手动提供的 RestHighLevelClient
bean(请参阅前面的部分)。
有了此配置后,可以像其他任何Spring bean一样注入 ElasticsearchRestTemplate
,如以下示例所示:
@Component
public class MyBean {
private final ElasticsearchRestTemplate template;
public MyBean(ElasticsearchRestTemplate template) {
this.template = template;
}
// ...
}
在存在 spring-data-elasticsearch
和使用 WebClient
所需的依赖关系(通常是 spring-boot-starter-webflux
)的情况下,
Spring Boot还可以将 ReactiveElasticsearchClient
和 ReactiveElasticsearchTemplate
自动配置为bean。它们与其他REST
客户端是等效的。
Spring Data Elasticsearch存储库
Spring Data包括对Elasticsearch的存储库支持。与前面讨论的JPA存储库一样,基本原理是根据方法名称自动为你构造查询。
实际上,Spring Data JPA和Spring Data Elasticsearch共享相同的通用基础设施。你可以从以前的JPA示例开始,并假设 City
现在是Elasticsearch
@Document
类而不是JPA @Entity
,它的工作方式相同。
有关Spring Data Elasticsearch的完整详细信息,请参阅 参考文档。 |
Spring Boot使用 ElasticsearchRestTemplate
或 ReactiveElasticsearchTemplate
bean支持经典和响应式Elasticsearch存储库。如果提供了所需的依赖项,这些bean很可能是通过Spring Boot自动配置的。
如果你希望使用自己的模板来支持Elasticsearch存储库,则可以添加自己的 ElasticsearchRestTemplate
或
ElasticsearchOperations
@Bean
,只要它名为 “elasticsearchTemplate
” 即可。同样适用于
ReactiveElasticsearchTemplate
和 ReactiveElasticsearchOperations
,其bean名称为
“reactiveElasticsearchTemplate
”。
你可以选择使用以下属性禁用存储库支持:
spring.data.elasticsearch.repositories.enabled=false
2.11.6. Cassandra
Cassandra 是一个开源的分布式数据库管理系统,旨在处理许多商用服务器上的大量数据。
Spring Boot为Cassandra提供自动配置,并由 Spring Data Cassandra在其之上提供抽象。
有一个 spring-boot-starter-data-cassandra
“Starter”,用于以方便的方式收集依赖项。
连接到Cassandra
你可以像使用其他任何Spring Bean一样注入自动配置的 CassandraTemplate
或Cassandra Session
实例。
spring.data.cassandra.*
属性可用于自定义连接。通常,你会提供 keyspace-name
和 contact-points
属性,如以下示例所示:
spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2
你还可以注册任意数量的Bean,这些Bean实现 ClusterBuilderCustomizer
以获得更高级的自定义。
以下代码清单显示了如何注入Cassandra bean:
@Component
public class MyBean {
private CassandraTemplate template;
@Autowired
public MyBean(CassandraTemplate template) {
this.template = template;
}
// ...
}
如果添加自己的 CassandraTemplate
类型的 @Bean
,它将替换默认值。
Spring Data Cassandra存储库
Spring Data包括对Cassandra的基本存储库支持。当前,这比前面讨论的JPA存储库受到更多限制,并且需要使用 @Query
注解finder方法。
有关Spring Data Cassandra的完整详细信息,请参阅 参考文档。 |
2.11.7. Couchbase
Couchbase 是一个开源,分布式,多模型的NoSQL面向文档的数据库,已针对交互式应用程序进行了优化。
Spring Boot为Couchbase提供自动配置,并由 Spring Data Couchbase在其之上提供抽象。
有 spring-boot-starter-data-couchbase
和 spring-boot-starter-data-couchbase-reactive
“Starters”,用于以方便的方式收集依赖项。
连接到Couchbase
你可以通过添加Couchbase SDK和一些配置来获取 Bucket
和 Cluster
。
spring.couchbase.*
属性可用于自定义连接。通常,你会提供引导主机,存储桶名称和密码,如以下示例所示:
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
spring.couchbase.bucket.name=my-bucket
spring.couchbase.bucket.password=secret
你 至少 需要提供引导主机,在这种情况下,存储桶名称为 default ,密码为空字符串。另外,你可以定义自己的
org.springframework.data.couchbase.config.CouchbaseConfigurer @Bean 来控制整个配置。
|
还可以自定义某些 CouchbaseEnvironment
设置。例如,以下配置更改了用于打开新 Bucket
并启用SSL支持的超时:
spring.couchbase.env.timeouts.connect=3000
spring.couchbase.env.ssl.key-store=/location/of/keystore.jks
spring.couchbase.env.ssl.key-store-password=secret
检查 spring.couchbase.env.*
属性以获取更多详细信息。
Spring Data Couchbase Repositories
Spring Data包括对Couchbase的存储库支持。有关Spring Data Couchbase的完整详细信息,请参阅 参考文档。
你可以像使用任何其他Spring Bean一样注入自动配置的 CouchbaseTemplate
实例,前提是提供的 默认 CouchbaseConfigurer
可用
(如前所述,当启用Couchbase支持时会发生这种情况)。
以下示例显示了如何注入Couchbase bean:
@Component
public class MyBean {
private final CouchbaseTemplate template;
@Autowired
public MyBean(CouchbaseTemplate template) {
this.template = template;
}
// ...
}
你可以在自己的配置中定义一些Bean,以覆盖自动配置所提供的那些:
-
一个名为
couchbaseTemplate
的CouchbaseTemplate
@Bean
。 -
一个名为
couchbaseIndexManager
的IndexManager
@Bean
。 -
一个名为
couchbaseCustomConversions
的CustomConversions
@Bean
。
为了避免在你自己的配置中对这些名称进行硬编码,你可以重用Spring Data Couchbase提供的 BeanNames
。
例如,你可以自定义要使用的转换器,如下所示:
@Configuration(proxyBeanMethods = false)
public class SomeConfiguration {
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
public CustomConversions myCustomConversions() {
return new CustomConversions(...);
}
// ...
}
如果要完全绕过Spring Data Couchbase的自动配置,请提供自己的 org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration 实现。
|
2.11.8. LDAP
LDAP(轻型目录访问协议)是一种开放的,与供应商无关的行业标准应用协议, 用于通过IP网络访问和维护分布式目录信息服务。Spring Boot为任何兼容的LDAP服务器提供自动配置, 并从 UnboundID支持嵌入式内存LDAP服务器。
LDAP抽象由 Spring Data LDAP提供。
有一个 spring-boot-starter-data-ldap
“Starter”,以方便的方式收集依赖项。
连接到LDAP服务器
要连接到LDAP服务器,请确保声明对 spring-boot-starter-data-ldap
“Starter”
或 spring-ldap-core
的依赖关系,然后在 application.properties
中声明服务器的URL,如下面的例子所示:
spring.ldap.urls=ldap://myserver:1235
spring.ldap.username=admin
spring.ldap.password=secret
如果需要自定义连接设置,则可以使用 spring.ldap.base
和 spring.ldap.base-environment
属性。
将基于这些设置自动配置 LdapContextSource
。如果 DirContextAuthenticationStrategy
Bean可用,
则将其与自动配置的 LdapContextSource
关联。如果你需要对其进行自定义(例如:使用 PooledContextSource
),
则仍然可以注入自动配置的 LdapContextSource
。确保将自定义的 ContextSource
标记为 @Primary
,以便自动配置的 LdapTemplate
使用它。
Spring Data LDAP存储库
Spring Data包括对LDAP的存储库支持。有关Spring Data LDAP的完整详细信息,请参阅 参考文档。
你还可以像使用其他任何Spring Bean一样注入自动配置的 LdapTemplate
实例,如以下示例所示:
@Component
public class MyBean {
private final LdapTemplate template;
@Autowired
public MyBean(LdapTemplate template) {
this.template = template;
}
// ...
}
嵌入式内存LDAP服务器
出于测试目的,Spring Boot支持从 UnboundID自动配置内存中的LDAP服务器。
要配置服务器,请添加 com.unboundid:unboundid-ldapsdk
依赖项,并声明 spring.ldap.embedded.base-dn
属性,如下所示:
spring.ldap.embedded.base-dn=dc=spring,dc=io
可以定义多个base-dn值,但是,由于可分辨的名称通常包含逗号,因此必须使用正确的符号来定义它们。 在yaml文件中,你可以使用yaml列表符号:
在属性文件中,必须将索引包括在属性名称中:
|
默认情况下,服务器在随机端口上启动并触发常规LDAP支持,无需指定 spring.ldap.urls
属性。
如果你的类路径上有一个 schema.ldif
文件,则该文件用于初始化服务器。如果要从其他资源加载初始化脚本,则也可以使用 spring.ldap.embedded.ldif
属性。
默认情况下,使用标准架构来验证 LDIF
文件。你可以通过设置 spring.ldap.embedded.validation.enabled
属性来完全关闭验证。
如果具有自定义属性,那么可以使用 spring.ldap.embedded.validation.schema
定义自定义属性类型或对象类。
2.11.9. InfluxDB
InfluxDB是一个开放源代码的时间序列数据库,已优化用于在操作监视,应用程序度量, 物联网传感器数据和实时分析等领域中快速,高可用性地存储和检索时间序列数据。
连接到InfluxDB
只要 influxdb-java
客户端位于类路径上并设置了数据库的URL,Spring Boot就会自动配置 InfluxDB
实例,如以下示例所示:
spring.influx.url=https://172.0.0.1:8086
如果与InfluxDB的连接需要用户和密码,则可以相应地设置 spring.influx.user
和 spring.influx.password
属性。
InfluxDB依赖OkHttp。如果需要在后台调整 InfluxDB
使用的http客户端,则可以注册 InfluxDbOkHttpClientBuilderProvider
bean。
2.12. 缓存
Spring框架提供了对向应用程序透明添加缓存的支持。从本质上讲,抽象将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。
缓存逻辑是透明应用的,不会对调用者造成任何干扰。只要通过 @EnableCaching
注解启用了缓存支持,Spring Boot就会自动配置缓存基础设施。
检查Spring Framework指南的 相关部分以获取更多详细信息。 |
简而言之,将缓存添加到服务的操作就像将相关注解添加到其方法一样容易,如以下示例所示:
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class MathService {
@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// ...
}
}
本示例说明了在潜在的昂贵操作上使用缓存的方法。在调用 computePiDecimal
之前,抽象将在 piDecimals
缓存中查找与 i
参数匹配的条目。
如果找到条目,则高速缓存中的内容会立即返回给调用方,并且不会调用该方法。否则,将调用该方法,并在返回值之前更新缓存。
你还可以透明地使用标准JSR-107(JCache)注解(例如:@CacheResult )。但是,我们强烈建议你不要混合使用Spring Cache和JCache注解。
|
如果你不添加任何特定的缓存库,Spring Boot会自动配置一个使用内存中concurrent maps的简单供应商。
当需要缓存时(例如:上例中的 piDecimals
),此供应商将为你创建它。实际上,不建议将该简单供应商用于生产环境,
但是它对于入门并确保你了解功能非常有用。确定要使用的缓存供应商后,请确保阅读其文档,以了解如何配置应用程序使用的缓存。
几乎所有供应商都要求你显式配置在应用程序中使用的每个缓存。有些提供自定义 spring.cache.cache-names
属性来定义默认缓存的方法。
2.12.1. 支持的缓存供应商
缓存抽象不提供实际的存储,而是依赖于由 org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
接口实现的抽象。
如果尚未定义 CacheManager
类型的Bean或名为 cacheResolver
的 CacheResolver
(请参阅 CachingConfigurer
),
则Spring Boot尝试检测以下供应商(按指示的顺序):
-
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
也可以通过设置 spring.cache.type 属性来 强制 指定特定的缓存供应商。如果你需要在某些环境(例如测试)中
完全禁用缓存,请使用此属性。
|
使用 spring-boot-starter-cache “Starter ”快速添加基本的缓存依赖项。入门程序提供了 spring-context-support 。
如果手动添加依赖项,则必须包括 spring-context-support 才能使用JCache,EhCache 2.x或Caffeine支持。
|
如果 CacheManager
是由Spring Boot自动配置的,则可以通过公开实现 CacheManagerCustomizer
接口的bean,
在完全初始化之前进一步调整其配置。下面的示例设置一个标志,指示应该将 null
值向下传递到基础映射:
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}
在前面的示例中,需要一个自动配置的 ConcurrentMapCacheManager 。
如果不是这种情况(你提供了自己的配置,或者自动配置了其他缓存供应商),则根本不会调用定制程序。
你可以根据需要拥有任意数量的定制程序,也可以使用 @Order 或 Ordered 对其进行排序。
|
泛型
如果上下文定义了 至少一个 org.springframework.cache.Cache
bean,则使用泛型缓存。
创建一个包装所有该类型Bean的 CacheManager
。
JCache (JSR-107)
通过在类路径上存在 javax.cache.spi.CachingProvider
引导 JCache(即,在类路径上存在符合JSR-107的缓存库),
并且 JCacheCacheManager
由 spring-boot-starter-cache
“Starter
”提供。
提供了各种兼容的库,Spring Boot为Ehcache 3,Hazelcast和Infinispan提供了依赖管理。也可以添加任何其他兼容的库。
可能会出现多个供应商,在这种情况下,必须明确指定供应商。即使JSR-107标准没有强制采用标准化的方式来定义配置文件的位置, Spring Boot也会尽其最大努力来容纳具有实现细节的缓存,如以下示例所示:
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml
当缓存库同时提供native实现和JSR-107支持时,Spring Boot会首选JSR-107支持,因此,如果你切换到其他JSR-107实现,则可以使用相同的功能。 |
Spring Boot对Hazelcast具有常规支持。
如果有单个 HazelcastInstance 可用,则除非指定了 spring.cache.jcache.config 属性,否则它也会自动用于 CacheManager 。
|
自定义基础 javax.cache.cacheManager
有两种方法:
-
可以在启动时通过设置
spring.cache.cache-names
属性来创建缓存。 如果自定义了javax.cache.configuration.Configuration
Bean,则将其用于自定义它们。 -
使用
CacheManager
的引用调用org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
Bean以进行完全定制。
如果定义了标准的 javax.cache.CacheManager bean,它将自动包装在抽象期望的 org.springframework.cache
.CacheManager 实现中。不再对其应用定制。
|
EhCache 2.x
如果可以在类路径的根目录下找到名为 ehcache.xml
的文件,则使用 EhCache 2.x。
如果找到EhCache 2.x,则使用 spring-boot-starter-cache
“Starter
”提供的 EhCacheCacheManager
来引导缓存管理器。
也可以提供备用配置文件,如以下示例所示:
spring.cache.ehcache.config=classpath:config/another-config.xml
Hazelcast
Spring Boot对Hazelcast具有常规支持。
如果已经自动配置了 HazelcastInstance
,则将其自动包装在 CacheManager
中。
Infinispan
Infinispan没有默认配置文件位置,因此必须明确指定。否则,将使用默认的引导程序。
spring.cache.infinispan.config=infinispan.xml
可以在启动时通过设置 spring.cache.cache-names
属性来创建缓存。
如果定义了自定义 ConfigurationBuilder
bean,则将其用于自定义缓存。
Spring Boot对Infinispan的支持仅限于嵌入式模式,并且非常基础。 如果你需要更多选择,则应该使用官方的Infinispan Spring Boot启动器。有关更多详细信息,请参见 Infinispan的文档。 |
Couchbase
如果可以使用 Couchbase Java客户端和 couchbase-spring-cache
实现,并且已配置Couchbase,则将自动配置 CouchbaseCacheManager
。
通过设置 spring.cache.cache-names
属性,还可以在启动时创建其他缓存。
这些缓存在自动配置的 Bucket
上运行。你 还 可以使用定制程序在另一个 Bucket
上创建其他缓存。
假设你在"main" Bucket
上需要两个缓存(cache1
和 cache2
),在"another" Bucket
上需要一个自定义的存活时间为2秒的缓存(cache3
)。
你可以通过配置创建前两个缓存,如下所示:
spring.cache.cache-names=cache1,cache2
然后,你可以定义一个 @Configuration
类来配置额外的 Bucket
和 cache3
缓存,如下所示:
@Configuration(proxyBeanMethods = false)
public class CouchbaseCacheConfiguration {
private final Cluster cluster;
public CouchbaseCacheConfiguration(Cluster cluster) {
this.cluster = cluster;
}
@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
}
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
return c -> {
c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
};
}
}
此示例配置重用了通过自动配置创建的 Cluster
。
Redis
如果 Redis可用并已配置,则 RedisCacheManager
将自动配置。
通过设置 spring.cache.cache-names
属性可以在启动时创建其他缓存,
并且可以使用 spring.cache.redis.*
属性配置缓存默认值。
例如,以下配置创建的 cache1
和 cache2
缓存的 存活时间 为10分钟:
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000
默认情况下,会添加键前缀,这样,如果两个单独的缓存使用相同的键,则Redis不会有重叠的键,也不会返回无效值。
如果你创建自己的 RedisCacheManager ,我们强烈建议将此设置保持启用状态。
|
你可以通过添加自己的 RedisCacheConfiguration @Bean 来完全控制配置。如果你要自定义序列化策略,这可能会很有用。
|
Caffeine
Caffeine是对Guava缓存的Java 8重写,取代了对Guava的支持。
如果存在Caffeine,则会自动配置 CaffeineCacheManager
(由 spring-boot-starter-cache
“Starter
”提供)。
缓存可以在启动时通过设置 spring.cache.cache-names
属性来创建,并且可以通过以下方式之一自定义(按指示的顺序):
-
由
spring.cache.caffeine.spec
定义的缓存规范 -
定义了一个
com.github.benmanes.caffeine.cache.CaffeineSpec
bean -
定义了一个
com.github.benmanes.caffeine.cache.Caffeine
bean
例如:以下配置将创建最大大小为500,存活时间 为10分钟的 cache1
和 cache2
缓存。
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
如果定义了 com.github.benmanes.caffeine.cache.CacheLoader
Bean,它将自动与 CaffeineCacheManager
关联。
由于 CacheLoader
将与由缓存管理器管理的 所有 缓存相关联,因此必须将其定义为 CacheLoader<Object, Object>
。
自动配置将忽略任何其他泛型类型。
Simple
如果找不到其他供应商,则配置使用 ConcurrentHashMap
作为缓存存储区的简单实现。如果你的应用程序中不存在任何缓存库,则这是默认设置。
默认情况下,将根据需要创建缓存,但是你可以通过设置 cache-names
属性来限制可用缓存的列表。
例如,如果只需要 cache1
和 cache2
高速缓存,请按如下所示设置 cache-names
属性:
spring.cache.cache-names=cache1,cache2
如果这样做,并且你的应用程序使用了未列出的缓存,那么当需要该缓存时,它将在运行时失败,但在启动时不会失败。 这与使用未声明的缓存时“实际”缓存供应商的行为类似。
None
当你的配置中存在 @EnableCaching
时,也需要合适的缓存配置。如果你需要在某些环境中完全禁用缓存,
请强制将缓存类型设置为 none
以使用no-op实现,如以下示例所示:
spring.cache.type=none
2.13. 消息
Spring Framework为与消息传递系统集成提供了广泛的支持,从使用 JmsTemplate
简化JMS API到使用完整的基础设施异步接收消息。
Spring AMQP为高级消息队列协议提供了类似的功能集。Spring Boot还为 RabbitTemplate
和RabbitMQ提供了自动配置选项。
Spring WebSocket本身就包含对STOMP消息的支持,而Spring Boot通过启动器和少量的自动配置对此提供了支持。
Spring Boot还支持Apache Kafka。
2.13.1. JMS
javax.jms.ConnectionFactory
接口提供了创建用于与JMS代理进行交互的 javax.jms.Connection
的标准方法。
尽管Spring需要一个 ConnectionFactory
来与JMS一起使用,但是你通常不需要自己直接使用它,而可以依赖于更高级别的消息传递抽象。
(有关详细信息,请参见Spring Framework参考文档的 相关部分。)Spring
Boot还会自动配置必要的基础设施,以发送和接收消息。
ActiveMQ支持
当 ActiveMQ在类路径上可用时,Spring Boot也可以配置 ConnectionFactory
。
如果存在broker,则将自动启动和配置嵌入式broker(前提是未通过配置指定代理URL)。
如果你使用 spring-boot-starter-activemq ,则将提供连接或嵌入ActiveMQ实例所需的依赖关系,
以及与JMS集成的Spring基础设施。
|
ActiveMQ配置由 spring.activemq.*
中的外部配置属性控制。
例如,你可以在 application.properties
中声明以下部分:
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
默认情况下,CachingConnectionFactory
用适当的设置包装native ConnectionFactory
,你可以通过 spring.jms.*
中的外部配置属性来控制这些设置:
spring.jms.cache.session-cache-size=5
如果你想使用native池,则可以通过向 org.messaginghub:pooled-jms
添加依赖项并相应地配置
JmsPoolConnectionFactory
来实现,如以下示例所示:
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
有关更多受支持的选项,请参见 ActiveMQProperties 。
你还可以注册任意数量的实现 ActiveMQConnectionFactoryCustomizer 的Bean,以进行更高级的自定义。
|
默认情况下,如果destination尚不存在ActiveMQ会创建,以便根据其提供的名称来解析destinations。
Artemis支持
当Spring Boot检测到 Artemis在类路径中可用时,它可以自动配置 ConnectionFactory
。
如果存在broker,则将自动启动和配置嵌入式broker(除非已明确设置mode属性)。
受支持的模式是 embedded
(以明确表明需要嵌入式broker,并且如果类路径上不存在该broker,则将发生错误)和
native
(使用Netty传输协议连接到broker)。配置后者后,Spring Boot会配置一个 ConnectionFactory
,
该工厂将使用默认设置连接到在本地计算机上运行的broker。
如果你使用 spring-boot-starter-artemis ,则将提供连接到现有Artemis实例所需的依赖项,以及与JMS集成的Spring基础设施。
将 org.apache.activemq:artemis-jms-server 添加到你的应用程序中可以使你使用嵌入式模式。
|
Artemis配置由 spring.artemis.*
中的外部配置属性控制。例如,你可以在 application.properties
中声明以下部分:
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret
嵌入broker时,可以选择是否要启用持久性并列出应使其可用的destinations。可以将它们指定为以逗号分隔的列表,以使用默认选项创建它们,
或者你可以定义 org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration
或
org.apache.activemq.artemis.jms.server.config.TopicConfiguration
类型的bean,分别用于高级队列和主题配置。
默认情况下,CachingConnectionFactory
用适当的设置包装native ConnectionFactory
,你可以通过
spring.jms.*
中的外部配置属性来控制这些设置:
spring.jms.cache.session-cache-size=5
如果你想使用native池,则可以通过向 org.messaginghub:pooled-jms
添加依赖项并相应地配置
JmsPoolConnectionFactory
来实现,如以下示例所示:
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
有关更多受支持的选项,请参见 ArtemisProperties
。
使用Artemis配置中的 name
属性或通过配置提供的名称,来根据destinations名称解析destinations,不涉及JNDI查找。
使用JNDI ConnectionFactory
如果你正在应用程序服务器中运行应用程序,Spring Boot会尝试使用JNDI来查找JMS ConnectionFactory
。
默认情况下,将检查 java:/JmsXA
和 java:/XAConnectionFactory
位置。
如果需要指定备用位置,则可以使用 spring.jms.jndi-name
属性,如以下示例所示:
spring.jms.jndi-name=java:/MyConnectionFactory
发送消息
Spring的 JmsTemplate
是自动配置的,你可以将其直接自动注入到自己的bean中,如以下示例所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}
JmsMessagingTemplate 可以类似的方式注入。
如果定义了 DestinationResolver 或 MessageConverter bean,则将其自动关联到自动配置的 JmsTemplate 。
|
接收消息
存在JMS基础设施时,可以使用 @JmsListener
注解任何bean以创建监听器端点。如果未定义 JmsListenerContainerFactory
,则会自动配置一个默认值。如果定义了 DestinationResolver
或 MessageConverter
Bean,则将其自动关联到默认工厂。
默认情况下,默认工厂是事务性的。如果你在存在 JtaTransactionManager
的基础设施中运行,则默认情况下它将与侦听器容器关联。
如果不是,则启用 sessionTransacted
标志。在后一种情况下,你可以通过在监听器方法(或其委托)上添加 @Transactional
来将本地数据存储事务与传入消息的处理相关联。这样可以确保本地事务完成后,接收的消息得到确认。这还包括发送已在同一JMS会话上执行的响应消息。
以下组件在 someQueue
目标上创建一个监听器端点:
@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}
有关更多详细信息,请参见 @EnableJms 的Javadoc。
|
如果你需要创建更多的 JmsListenerContainerFactory
实例,或者想要覆盖默认实例,Spring
Boot提供了一个 DefaultJmsListenerContainerFactoryConfigurer
,你可以使用它来初始化具有与自动配置相同设置的 DefaultJmsListenerContainerFactory
。
例如,以下示例公开了另一个使用特定 MessageConverter
的工厂:
@Configuration(proxyBeanMethods = false)
static class JmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory());
factory.setMessageConverter(myMessageConverter());
return factory;
}
}
然后,可以在任何 @JmsListener
注释的方法中使用工厂,如下所示:
@Component
public class MyBean {
@JmsListener(destination = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
2.13.2. AMQP
Advanced Message Queuing Protocol (AMQP) 是面向消息中间件的与平台无关的有线级别协议。
Spring AMQP项目将Spring的核心概念应用于基于AMQP的消息传递解决方案的开发。
Spring Boot为通过RabbitMQ使用AMQP提供了许多便利,包括 spring-boot-starter-amqp
“Starter
”。
RabbitMQ支持
RabbitMQ是基于AMQP协议的轻型,可靠,可伸缩和便携式消息broker。
Spring使用 RabbitMQ
通过AMQP协议进行通信。
RabbitMQ配置由 spring.rabbitmq.*
中的外部配置属性控制。例如,你可以在 application.properties
中声明以下部分:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
另外,你可以使用 addresses
属性配置相同的连接:
spring.rabbitmq.addresses=amqp://admin:secret@localhost
如果上下文中存在 ConnectionNameStrategy
Bean,它将自动用于命名由自动配置的 ConnectionFactory
创建的连接。
有关更多受支持的选项,请参见 RabbitProperties
。
有关更多详细信息,请参阅 了解RabbitMQ使用的AMQP协议。 |
发送消息
Spring的 AmqpTemplate
和 AmqpAdmin
是自动配置的,你可以将它们直接自动注入到自己的bean中,如以下示例所示:
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final AmqpAdmin amqpAdmin;
private final AmqpTemplate amqpTemplate;
@Autowired
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
}
// ...
}
RabbitMessagingTemplate 可以类似的方式注入。
如果定义了 MessageConverter bean,它将自动关联到自动配置的 AmqpTemplate 。
|
如有必要,任何定义为 org.springframework.amqp.core.Queue
的bean都会自动用于在RabbitMQ实例上声明相应的队列。
要重试操作,可以在 AmqpTemplate
上启用重试(例如,在broker连接丢失的情况下):
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s
默认情况下,重试是禁用的。你也可以通过声明 RabbitRetryTemplateCustomizer
bean来以编程方式自定义 RetryTemplate
。
接收消息
存在Rabbit基础设施时,可以使用 @RabbitListener
注解任何bean以创建监听器端点。
如果未定义 RabbitListenerContainerFactory
,则会自动配置默认的 SimpleRabbitListenerContainerFactory
,
你可以使用 spring.rabbitmq.listener.type
属性切换到直接容器。
如果定义了 MessageConverter
或 MessageRecoverer
Bean,它将自动与默认工厂关联。
以下示例组件在 someQueue
队列上创建一个监听器端点:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}
}
有关更多详细信息,请参见 @EnableRabbit 的Javadoc。
|
如果你需要创建更多 RabbitListenerContainerFactory
实例,或者想要覆盖默认实例,
Spring Boot提供了一个 SimpleRabbitListenerContainerFactoryConfigurer
和 DirectRabbitListenerContainerFactoryConfigurer
,
你可以使用它们来初始化 SimpleRabbitListenerContainerFactory
和 DirectRabbitListenerContainerFactory
,其设置与自动配置所使用的工厂相同。
选择哪种容器都没有关系。这两个bean通过自动配置公开。 |
例如,以下配置类公开了另一个使用特定 MessageConverter
的工厂:
@Configuration(proxyBeanMethods = false)
static class RabbitConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
}
}
然后,你可以在任何 @RabbitListener
注释的方法中使用工厂,如下所示:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
你可以启用重试来处理监听器引发异常的情况。默认情况下,使用 RejectAndDontRequeueRecoverer
,
但是你可以定义自己的 MessageRecoverer
。当重试耗尽时,消息将被拒绝,如果将broker配置为这样做,则消息将被丢弃或路由到死信交换器。
默认情况下,重试是禁用的。你也可以通过声明 RabbitRetryTemplateCustomizer
bean来以编程方式自定义 RetryTemplate
。
默认情况下,如果禁用了重试,并且监听器抛出异常,则会无限期地重试传递。你可以通过两种方式修改此行为:
将 defaultRequeueRejected 属性设置为 false ,以便尝试零次重新传递,或者引发
AmqpRejectAndDontRequeueException 以指示应拒绝该消息。后者是启用重试并达到最大传递尝试次数时使用的机制。
|
2.13.3. Apache Kafka支持
通过提供 spring-kafka
项目的自动配置来支持 Apache Kafka。
Kafka配置由 spring.kafka.*
中的外部配置属性控制。例如,你可以在 application.properties
中声明以下部分:
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup
要在启动时创建主题,请添加 NewTopic 类型的Bean。如果该主题已经存在,则将忽略该Bean。
|
有关更多受支持的选项,请参见 KafkaProperties
。
发送消息
Spring的 KafkaTemplate
是自动配置的,你可以直接在自己的bean中自动对其进行注入,如以下示例所示:
@Component
public class MyBean {
private final KafkaTemplate kafkaTemplate;
@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
// ...
}
如果定义了 spring.kafka.producer.transaction-id-prefix 属性,则会自动配置 KafkaTransactionManager 。
另外,如果定义了 RecordMessageConverter bean,它将自动关联到自动配置的 KafkaTemplate 。
|
接收消息
存在Apache Kafka基础设施时,可以使用 @KafkaListener
注释任何bean以创建监听器端点。
如果未定义 KafkaListenerContainerFactory
,则会使用 spring.kafka.listener.*
中定义的键自动配置默认值。
以下组件在 someTopic
主题上创建监听器端点:
@Component
public class MyBean {
@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
}
}
如果定义了 KafkaTransactionManager
bean,它将自动关联到容器工厂。同样,如果定义了 ErrorHandler
,AfterRollbackProcessor
或 ConsumerAwareRebalanceListener
bean,它将自动与默认工厂关联。
根据监听器类型,将 RecordMessageConverter
或 BatchMessageConverter
bean与默认工厂关联。
如果对于批处理监听器仅存在一个 RecordMessageConverter
bean,则将其包装在 BatchMessageConverter
中。
自定义 ChainedKafkaTransactionManager 必须标记为 @Primary ,因为它通常引用自动配置的 KafkaTransactionManager bean。
|
Kafka流
用于Apache Kafka的Spring提供了一个工厂bean来创建 StreamsBuilder
对象并管理其流的生命周期。
只要 kafka-streams
在类路径上并且通过 @EnableKafkaStreams
注解启用Kafka Streams,
Spring Boot就会自动配置所需的 KafkaStreamsConfiguration
bean。
启用Kafka Streams意味着必须设置应用程序ID和引导服务器。
可以使用 spring.kafka.streams.application-id
来配置前者,如果未设置,则默认为 spring.application.name
。
后者可以全局设置,也可以仅针对流进行覆盖。
使用专用属性可以获得几个附加属性。可以使用 spring.kafka.streams.properties
命名空间设置其他任意Kafka属性。
另请参见Kafka的其他属性。
要使用工厂bean,只需将 StreamsBuilder
连接到你的 @Bean
中,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableKafkaStreams
public static class KafkaStreamsExampleConfiguration {
@Bean
public KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {
KStream<Integer, String> stream = streamsBuilder.stream("ks1In");
stream.map((k, v) -> new KeyValue<>(k, v.toUpperCase())).to("ks1Out",
Produced.with(Serdes.Integer(), new JsonSerde<>()));
return stream;
}
}
默认情况下,由它创建的 StreamBuilder
对象管理的流将自动启动。你可以使用 spring.kafka.streams.auto-startup
属性来自定义此行为。
Kafka的其他属性
自动配置支持的属性显示在 通用应用程序属性中。 请注意,在大多数情况下,这些属性(hyphenated或camelCase)直接映射到Apache Kafka dotted属性。有关详细信息,请参阅Apache Kafka文档。
这些属性的前几个属性适用于所有组件(生产者,消费者,管理员和流),但如果你希望使用不同的值,则可以在组件级别上指定。 Apache Kafka指定属性的重要性为HIGH,MEDIUM或LOW。Spring Boot自动配置支持所有HIGH重要性属性,一些选定的MEDIUM和LOW属性以及任何没有默认值的属性。
通过 KafkaProperties
类可以直接使用Kafka支持的属性的子集。如果希望使用不直接支持的其他属性来配置生产者或消费者,请使用以下属性:
spring.kafka.properties.prop.one=first
spring.kafka.admin.properties.prop.two=second
spring.kafka.consumer.properties.prop.three=third
spring.kafka.producer.properties.prop.four=fourth
spring.kafka.streams.properties.prop.five=fifth
这将常见的 prop.one
Kafka属性设置为 first
(适用于生产者,消费者和管理员),prop.two
管理员属性设置为 second
,
prop.three
消费者属性设置为 third
,prop.four
生产者属性设置为 fourth
,prop.five
流属性设置为 fifth
。
你还可以如下配置Spring Kafka JsonDeserializer
:
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.value.default.type=com.example.Invoice
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example,org.acme
同样,你可以禁用 JsonSerializer
在头部发送类型信息的默认行为:
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.properties.spring.json.add.type.headers=false
以这种方式设置的属性将覆盖Spring Boot显式支持的任何配置项。 |
使用嵌入式Kafka进行测试
Spring for Apache Kafka提供了一种使用嵌入式Apache Kafka broker测试项目的便捷方法。
要使用此功能,请在 spring-kafka-test
模块中使用 @EmbeddedKafka
注释测试类。
有关更多信息,请参阅Spring for Apache Kafka 参考手册。
要使Spring Boot自动配置与上述嵌入式Apache Kafka broker一起使用,你需要将嵌入式broker地址(由 EmbeddedKafkaBroker
填充)
的系统属性重新映射到Apache Kafka的Spring Boot配置属性中。有几种方法可以做到这一点:
-
提供一个系统属性,以将嵌入式broker地址映射到测试类中的
spring.kafka.bootstrap-servers
中:
static {
System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers");
}
-
在
@EmbeddedKafka
注解上配置属性名称:
@EmbeddedKafka(topics = "someTopic",
bootstrapServersProperty = "spring.kafka.bootstrap-servers")
-
在配置属性中使用占位符:
spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}
2.14. 使用 RestTemplate
调用REST服务
如果你需要从应用程序中调用远程REST服务,则可以使用Spring Framework的 RestTemplate
类。
由于 RestTemplate
实例在使用前通常需要自定义,因此Spring Boot不提供任何单个自动配置的 RestTemplate
bean。
但是,它确实会自动配置 RestTemplateBuilder
,可在需要时将其用于创建 RestTemplate
实例。
自动配置的 RestTemplateBuilder
确保将明智的 HttpMessageConverters
应用于 RestTemplate
实例。
以下代码显示了一个典型示例:
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
}
}
RestTemplateBuilder 包含许多有用的方法,可用于快速配置 RestTemplate 。例如:要添加BASIC身份验证支持,
可以使用 builder.basicAuthentication("user", "password").build() 。
|
2.14.1. RestTemplate自定义
RestTemplate
自定义有三种主要方法,具体取决于你要应用自定义的范围。
为了使所有自定义项的作用域尽可能狭窄,请注入自动配置的 RestTemplateBuilder
,然后根据需要调用其方法。
每个方法调用都返回一个新的 RestTemplateBuilder
实例,因此自定义项仅影响此builder的使用。
要进行应用程序作用域的附加自定义,请使用 RestTemplateCustomizer
bean。
所有此类bean都会自动注册到自动配置的 RestTemplateBuilder
中,并应用于使用它构建的任何模板。
以下示例显示了一个定制程序,该定制程序为除 192.168.0.5
之外的所有主机配置使用代理:
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
}
}
最后,最极端(很少使用)的选项是创建自己的 RestTemplateBuilder
bean。
这样做会关闭 RestTemplateBuilder
的自动配置,并阻止使用任何 RestTemplateCustomizer
Bean。
2.15. 使用 WebClient
调用REST服务
如果你的类路径中包含Spring WebFlux,则还可以选择使用 WebClient
调用远程REST服务。
与 RestTemplate
相比,此客户端具有更强的功能性,并且是完全响应性的。
你可以在 Spring Framework文档的专用部分中了解有关 WebClient
的更多信息。
Spring Boot为你创建并预配置了 WebClient.Builder
。强烈建议将其注入你的组件中,并使用它来创建 WebClient
实例。
Spring Boot将该builder配置为共享HTTP资源,以与服务器相同的方式反映编解码器的设置
(请参阅WebFlux HTTP codecs自动配置),等等。
以下代码显示了一个典型示例:
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://example.org").build();
}
public Mono<Details> someRestCall(String name) {
return this.webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details.class);
}
}
2.15.1. WebClient运行时
Spring Boot将根据应用程序类路径上可用的库自动检测要使用哪个 ClientHttpConnector
来驱动 WebClient
。
目前支持Reactor Netty和Jetty RS客户端。
spring-boot-starter-webflux
启动器默认情况下依赖于 io.projectreactor.netty:reactor-netty
,
这带来了服务器和客户端的实现。如果选择使用Jetty作为响应式服务器,则应该添加对Jetty响应式HTTP客户端库
org.eclipse.jetty:jetty-reactive-httpclient
的依赖。
对服务器和客户端使用相同的技术具有优势,因为它将自动在客户端和服务器之间共享HTTP资源。
通过提供自定义的 JettyResourceFactory
或 ReactorResourceFactory
bean,开发人员可以覆盖Jetty和Reactor
Netty的资源配置 — 这将同时应用于客户端和服务器。
如果你希望为客户端覆盖该选项,则可以定义自己的 ClientHttpConnector
bean,并完全控制客户端配置。
2.15.2. WebClient自定义
WebClient
自定义有三种主要方法,具体取决于你希望自定义应用的范围。
为了使所有自定义项的作用域尽可能狭窄,请注入自动配置的 WebClient.Builder
,然后根据需要调用其方法。
WebClient.Builder
实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有客户端中。
如果要使用同一构建器创建多个客户端,则还可以考虑使用 WebClient.Builder other = builder.clone();
克隆该构建器。
要对所有 WebClient.Builder
实例进行应用程序作用域的附加自定义,可以声明 WebClientCustomizer
bean
并在注入点本地更改 WebClient.Builder
。
最后,你可以回退到原始API并使用 WebClient.create()
。在这种情况下,不会应用任何自动配置或 WebClientCustomizer
。
2.16. 验证
只要JSR-303实现(例如:Hibernate验证器)位于类路径上,就会自动启用Bean验证1.1支持的方法验证功能。
这使bean方法的参数和/或返回值可以使用 javax.validation
约束进行注解。
具有此类注解方法的目标类需要在类型级别使用 @Validated
注解进行注释,以便在其方法中搜索内联约束注解。
例如:以下服务触发第一个参数的验证,确保其大小在8到10之间:
@Service
@Validated
public class MyBean {
public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
Author author) {
...
}
}
2.17. 发送邮件
Spring Framework通过使用 JavaMailSender
接口提供了用于发送电子邮件的简单抽象,Spring Boot为它提供了自动配置以及starter模块。
有关如何使用 JavaMailSender 的详细说明,请参见 参考文档。
|
如果 spring.mail.host
和相关库(由 spring-boot-starter-mail
定义)可用,且不存在默认 JavaMailSender
,
则创建一个。可以通过 spring.mail
命名空间中的配置项进一步自定义sender。
有关更多详细信息,请参见 MailProperties
。
特别是,某些默认超时值是无限的,你可能需要更改此值,以避免线程被无响应的邮件服务器阻塞,如以下示例所示:
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000
也可以使用来自JNDI的现有 Session
配置 JavaMailSender
:
spring.mail.jndi-name=mail/Session
设置 jndi-name
时,它优先于所有其他与Session相关的其他设置。
2.18. JTA的分布式事务
当检测到JTA环境时,将使用Spring的 JtaTransactionManager
来管理事务。
自动配置的JMS,DataSource和JPA Bean已升级为支持XA事务。
你可以使用标准的Spring习惯用法(例如:@Transactional
)来参与分布式事务。
如果你在JTA环境中,并且仍要使用本地事务,则可以将 spring.jta.enabled
属性设置为 false
以禁用JTA自动配置。
2.18.1. 使用Atomikos事务管理器
Atomikos是一种流行的开源事务管理器,可以嵌入到你的Spring Boot应用程序中。
你可以使用 spring-boot-starter-jta-atomikos
启动器引入相应的Atomikos库。
Spring Boot自动配置Atomikos,并确保将适当的 depends-on
设置应用于Spring Bean,以实现正确的启动和关闭顺序。
默认情况下,Atomikos事务日志将写入应用程序主目录(应用程序jar文件所在的目录)中的 transaction-logs
目录。
你可以通过在 application.properties
文件中设置 spring.jta.log-dir
属性来自定义此目录的位置。
以 spring.jta.atomikos.properties
开头的属性也可以用于自定义Atomikos UserTransactionServiceImp
。
有关完整的详细信息,请参见 AtomikosProperties
Javadoc。
为了确保多个事务管理器可以安全地协调同一资源管理器,必须为每个Atomikos实例配置一个唯一的ID。
默认情况下,此ID是运行Atomikos的计算机的IP地址。为确保生产中的唯一性,应为每个应用程序实例将
spring.jta.transaction-manager-id 属性配置为不同的值。
|
2.18.2. 使用Bitronix事务管理器
Bitronix是流行的开源JTA事务管理器实现。
你可以使用 spring-boot-starter-jta-bitronix
启动器将适当的Bitronix依赖项添加到项目中。
与Atomikos一样,Spring Boot自动配置Bitronix并对你的bean进行后处理,以确保启动和关闭顺序正确。
默认情况下,Bitronix事务日志文件(part1.btm
和 part2.btm
)被写入应用程序主目录中的 transaction-logs
目录。
你可以通过设置 spring.jta.log-dir
属性来自定义此目录的位置。以 spring.jta.bitronix.properties
开头的属性也绑定到 bitronix.tm.Configuration
Bean,从而可以进行完全自定义。
有关详细信息,请参见 Bitronix文档。
为了确保多个事务管理器可以安全地协调同一资源管理器,必须为每个Bitronix实例配置唯一的ID。
默认情况下,此ID是运行Bitronix的计算机的IP地址。为确保生产中的唯一性,应为每个应用程序实例将
spring.jta.transaction-manager-id 属性配置为不同的值。
|
2.18.3. 使用Java EE托管事务管理器
如果将Spring Boot应用程序打包为 war
或 ear
文件,并将其部署到Java EE应用程序服务器,则可以使用应用程序服务器的内置事务管理器。
Spring Boot通过查看常见的JNDI位置(java:comp/UserTransaction
, java:comp/TransactionManager
等)来尝试自动配置事务管理器。
如果使用应用程序服务器提供的事务服务,通常还需要确保所有资源都由服务器管理并通过JNDI公开。
Spring Boot尝试通过在JNDI路径(java:/JmsXA
或 java:/XAConnectionFactory
)中查找 ConnectionFactory
来自动配置JMS,
并且你可以使用 spring.datasource.jndi-name
属性配置你的 DataSource
。
2.18.4. 混合XA和非XA JMS连接
使用JTA时,主要的JMS ConnectionFactory
bean是XA-aware,并参与分布式事务。
在某些情况下,你可能想通过使用非XA ConnectionFactory
处理某些JMS消息。
例如:你的JMS处理逻辑可能需要比XA超时更长的时间。
如果要使用非XA ConnectionFactory
,则可以注入 nonXaJmsConnectionFactory
bean,
而不是 @Primary
jmsConnectionFactory
bean。
为了保持一致性,还可使用bean别名 xaJmsConnectionFactory
提供了 jmsConnectionFactory
bean。
以下示例显示如何注入 ConnectionFactory
实例:
// Inject the primary (XA aware) ConnectionFactory
@Autowired
private ConnectionFactory defaultConnectionFactory;
// Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;
// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;
2.18.5. 支持替代嵌入式事务管理器
XAConnectionFactoryWrapper
和
XADataSourceWrapper
接口可用于支持其他嵌入式事务管理器。
这些接口负责包装 XAConnectionFactory
和 XADataSource
Bean,并将它们作为常规的 ConnectionFactory
和
DataSource
Bean公开,以透明方式注册分布式事务。如果你在 ApplicationContext
中注册了
JtaTransactionManager
bean和适当的XA包装bean,则 DataSource
和JMS自动配置使用JTA变体。
BitronixXAConnectionFactoryWrapper和 BitronixXADataSourceWrapper 提供了有关如何编写XA包装器的良好示例。
2.19. Hazelcast
如果 Hazelcast位于类路径上,并且找到了合适的配置,
则Spring Boot会自动配置一个 HazelcastInstance
,你可以将其注入应用程序中。
如果定义 com.hazelcast.config.Config
bean,Spring Boot会使用它。
如果你的配置定义了一个实例名称,Spring Boot会尝试查找现有实例,而不是创建一个新实例。
你还可以通过配置指定使用的Hazelcast配置文件,如以下示例所示:
spring.hazelcast.config=classpath:config/my-hazelcast.xml
否则,Spring Boot会尝试从默认位置查找Hazelcast配置:
工作目录中或类路径根目录中的 hazelcast.xml
,或相同位置中的 .yaml
副本。
我们还检查是否设置了 hazelcast.config
系统属性。有关更多详细信息,请参见
Hazelcast文档。
如果在类路径中存在 hazelcast-client
,Spring Boot首先尝试通过检查以下配置选项来创建客户端:
-
com.hazelcast.client.config.ClientConfig
bean的存在。 -
由
spring.hazelcast.config
属性定义的配置文件。 -
hazelcast.client.config
系统属性的存在。 -
工作目录中或类路径根目录中的
hazelcast-client.xml
。 -
工作目录中或类路径根目录中的
hazelcast-client.yaml
。
Spring Boot还具有对Hazelcast的显式缓存支持。
如果启用了缓存,则 HazelcastInstance 将自动包装在 CacheManager 实现中。
|
2.20. Quartz调度器
Spring Boot为使用 Quartz scheduler提供了许多便利,包括
spring-boot-starter-quartz
“Starter”。如果Quartz可用,则自动配置 Scheduler
(通过 SchedulerFactoryBean
抽象)。
以下类型的Bean将自动被拾取并与 Scheduler
关联:
-
JobDetail
: 定义一个特定的Job。JobDetail
实例可以使用JobBuilder API构建。 -
Calendar
. -
Trigger
: 定义何时触发特定job。
默认情况下,使用内存中的 JobStore
。但是,如果应用程序中有可用的 DataSource
bean,并且相应地配置了
spring.quartz.job-store-type
属性,则可以配置基于JDBC的存储,如以下示例所示:
spring.quartz.job-store-type=jdbc
使用JDBC存储时,可以在启动时初始化schema,如以下示例所示:
spring.quartz.jdbc.initialize-schema=always
默认情况下,使用Quartz库随附的标准脚本检测并初始化数据库。这些脚本将删除现有表,并在每次重新启动时删除所有触发器。
还可以通过设置 spring.quartz.jdbc.schema 属性来提供自定义脚本。
|
要使Quartz使用应用程序的主 DataSource
以外的 DataSource
,
请声明一个 DataSource
bean,并用 @QuartzDataSource
注解其 @Bean
方法。
这样可以确保 SchedulerFactoryBean
和Schema初始化都使用特定于Quartz的 DataSource
。
默认情况下,通过配置创建的jobs将不会覆盖从持久性job存储中读取的已注册jobs。要启用覆盖现有作业定义的功能,
请设置 spring.quartz.overwrite-existing-jobs
属性。
可以使用 spring.quartz
属性和 SchedulerFactoryBeanCustomizer
bean来定制Quartz Scheduler配置,
这允许以编程方式进行 SchedulerFactoryBean
定制。可以使用 spring.quartz.properties.*
自定义高级Quartz配置属性。
特别是,Executor bean没有与调度程序关联,因为Quartz提供了一种通过 spring.quartz.properties
配置调度程序的方法。如果需要自定义任务执行程序,请考虑实现 SchedulerFactoryBeanCustomizer 。
|
Jobs可以定义设置器以注入数据映射属性。常规beans也可以用类似的方式注入,如以下示例所示:
public class SampleJob extends QuartzJobBean {
private MyService myService;
private String name;
// Inject "MyService" bean
public void setMyService(MyService myService) { ... }
// Inject the "name" job data property
public void setName(String name) { ... }
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
...
}
}
2.21. 任务执行和调度
在上下文中没有 Executor
bean的情况下,Spring Boot会使用合理的默认值自动配置 ThreadPoolTaskExecutor
,
这些默认值可以自动与异步任务执行(@EnableAsync
)和Spring MVC异步请求处理相关联。
如果你在上下文中定义一个自定义 自动配置的 |
线程池使用8个核心线程,这些线程可以根据负载增长和收缩。可以使用 spring.task.execution
命名空间微调这些默认设置,如以下示例所示:
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
这会将线程池更改为使用有界队列,以便在队列已满(100个任务)时,线程池最多增加到16个线程。 池的收缩更加激进,因为当线程空闲10秒(而不是默认情况下的60秒)时,它们将被回收。
如果需要将 ThreadPoolTaskScheduler
与计划的任务执行(@EnableScheduling
)关联,也可以对其进行自动配置。
线程池默认使用一个线程,可以使用 spring.task.scheduling
命名空间对这些设置进行微调。
如果需要创建自定义执行器或调度器,则可以在上下文中使用 TaskExecutorBuilder
bean和 TaskSchedulerBuilder
bean。
2.22. Spring Integration
Spring Boot为使用 Spring Integration提供了许多便利,包括
spring-boot-starter-integration
“Starter
”。
Spring Integration提供消息传递以及其他传输(例如:HTTP,TCP等)的抽象。
如果Spring Integration在你的类路径中可用,则通过 @EnableIntegration
注解对其进行初始化。
Spring Boot还配置了一些功能,这些功能由其他Spring Integration模块的存在触发。
如果 spring-integration-jmx
也位于类路径上,则消息处理统计信息将通过JMX发布。
如果 spring-integration-jdbc
可用,则可以在启动时创建默认的数据库schema,如以下行所示:
spring.integration.jdbc.initialize-schema=always
有关更多详细信息,请参见 IntegrationAutoConfiguration
和 IntegrationProperties
类。
默认情况下,如果存在Micrometer meterRegistry
bean,那么Spring Integration指标将由Micrometer管理。
如果你希望使用旧版Spring Integration指标,请将 DefaultMetricsFactory
bean添加到应用程序上下文中。
2.23. Spring Session
Spring Boot为各种数据存储提供了 Spring Session自动配置。在构建Servlet Web应用程序时,可以自动配置以下存储:
-
JDBC
-
Redis
-
Hazelcast
-
MongoDB
构建响应式Web应用程序时,可以自动配置以下存储:
-
Redis
-
MongoDB
如果类路径上存在单个Spring Session模块,则Spring Boot会自动使用该存储实现。
如果你有多个实现,则必须选择要用于存储会话的 StoreType
。
例如:要将JDBC用作后端存储,可以按以下方式配置应用程序:
spring.session.store-type=jdbc
你可以通过将 store-type 设置为 none 来禁用Spring Session。
|
每个存储都有特定的附加设置。例如:可以为JDBC存储定制表的名称,如以下示例所示:
spring.session.jdbc.table-name=SESSIONS
要设置会话的超时时间,可以使用 spring.session.timeout
属性。如果未设置该属性,则自动配置将降级到 server.servlet.session.timeout
的值。
2.24. 通过JMX进行监视和管理
Java Management Extensions (JMX) 提供了监视和管理应用程序的标准机制。
Spring Boot将最合适的 MBeanServer
公开为ID为 mbeanServer
的bean。
带有Spring JMX注解(@ManagedResource
,@ManagedAttribute
或 @ManagedOperation
)的任何bean都可以使用它。
如果你的平台提供了标准的 MBeanServer
,则Spring Boot将使用该标准,并在必要时默认使用VM MBeanServer
。
如果所有操作失败,将创建一个新的 MBeanServer
。
有关更多详细信息,请参阅 JmxAutoConfiguration
类。
2.25. 测试
请移步 这里。
2.26. WebSockets
Spring Boot为嵌入式Tomcat,Jetty和Undertow提供了WebSockets自动配置。 如果将war文件部署到独立容器,Spring Boot会假定该容器负责其WebSocket支持的配置。
Spring Framework为MVC Web应用程序提供了 丰富的WebSocket支持,
可以通过 spring-boot-starter-websocket
模块轻松访问。
WebSocket支持也可用于 响应式Web应用程序,
需要在 spring-boot-starter-webflux
旁包含WebSocket API:
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>
2.27. Web服务
Spring Boot提供了Web服务自动配置,因此你所要做的就是定义 Endpoints
。
使用 spring-boot-starter-webservices
模块可以轻松访问 Spring Web Services功能。
可以分别为你的WSDL和XSD自动创建 SimpleWsdl11Definition
和 SimpleXsdSchema
Bean。为此请配置其位置,如以下示例所示:
spring.webservices.wsdl-locations=classpath:/wsdl
2.27.1. 使用 WebServiceTemplate
调用Web服务
如果需要从应用程序中调用远程Web服务,则可以使用 WebServiceTemplate
类。
由于 WebServiceTemplate
实例在使用前通常需要自定义,因此Spring Boot不提供任何单个自动配置的 WebServiceTemplate
bean。
但是,它会自动配置 WebServiceTemplateBuilder
,可在需要时将其用于创建 WebServiceTemplate
实例。
以下代码显示了一个典型示例:
@Service
public class MyService {
private final WebServiceTemplate webServiceTemplate;
public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
this.webServiceTemplate = webServiceTemplateBuilder.build();
}
public DetailsResp someWsCall(DetailsReq detailsReq) {
return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION));
}
}
默认情况下,WebServiceTemplateBuilder
使用类路径上的可用HTTP客户端库来检测合适的基于HTTP的 WebServiceMessageSender
。
你还可以像下面那样自定义读取和连接超时:
@Bean
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
return builder.messageSenders(new HttpWebServiceMessageSenderBuilder()
.setConnectTimeout(5000).setReadTimeout(2000).build()).build();
}
2.28. 创建自己的自动配置
如果你在开发共享库的公司中工作,或者在开源或商业库中工作,则可能需要开发自己的自动配置。自动配置类可以捆绑在外部jar中,并且仍由Spring Boot拾取。
自动配置可以与“starter
”相关联,该“starter
”提供自动配置代码以及你将使用的典型库。
我们首先介绍构建自己的自动配置所需的知识,然后继续介绍创建自定义启动器所需的典型步骤。
有一个 demo项目可以展示如何逐步创建starter。 |
2.28.1. 了解自动配置的Bean
在后台,自动配置是通过标准 @Configuration
类实现的。其他 @Conditional
注解用于约束何时应应用自动配置。
通常,自动配置类使用 @ConditionalOnClass
和 @ConditionalOnMissingBean
注解。
这样可以确保仅当找到相关的类并且没有声明自己的 @Configuration
时,才应用自动配置。
你可以浏览 spring-boot-autoconfigure
的源代码以查看Spring提供的
@Configuration
类(请参阅 META-INF/spring.factories
文件)。
2.28.2. 查找自动配置候选人
Spring Boot检查发布的jar中是否存在 META-INF/spring.factories
文件。
该文件应在 EnableAutoConfiguration
键下列出你的配置类,如以下示例所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\ com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
自动配置 只能 以这种方式加载。
确保在特定的程序包空间中定义它们,并且决不要将它们作为组件扫描的目标。
此外,自动配置类不应启用组件扫描以查找其他组件。应该使用特定的 @Imports 代替。
|
如果需要按特定顺序应用配置,则可以使用 @AutoConfigureAfter
或
@AutoConfigureBefore
注解。
例如:如果你提供特定于Web的配置,则可能需要在 WebMvcAutoConfiguration
之后应用你的类。
如果要排序某些彼此之间不具有任何直接了解的自动配置,则也可以使用 @AutoConfigureOrder
。
该注解与常规 @Order
注解具有相同的语义,但为自动配置类提供了专用的顺序。
2.28.3. 条件注解
你几乎总是希望在自动配置类中包含一个或多个 @Conditional
注解。
@ConditionalOnMissingBean
注解是一个常见示例,用于使开发人员在对默认设置不满意的情况下覆盖自动配置。
Spring Boot包含许多 @Conditional
注解,你可以通过标注 @Configuration
类或单个 @Bean
方法在自己的代码中重用它。
这些注解包括:
Class条件
通过 @ConditionalOnClass
和 @ConditionalOnMissingClass
注解,可以根据是否存在特定类来包含 @Configuration
类。
由于注解元数据是通过使用 ASM进行解析的,因此即使该类可能实际上未出现在正在运行的应用程序类路径上,
你也可以使用 value
属性来引用真实的类。如果你更喜欢通过使用 String
值来指定类名称,则也可以使用 name
属性。
这种机制不适用于通常将返回类型作为该条件目标的 @Bean
方法:在方法上的条件应用之前,JVM将加载该类和可能处理的方法引用,如果类不存在,这些引用将失败。
为了处理这种情况,可以使用单独的 @Configuration
类隔离条件,如以下示例所示:
@Configuration(proxyBeanMethods = false)
// Some conditions
public class MyAutoConfiguration {
// Auto-configured beans
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedAcmeService.class)
static class EmbeddedConfiguration {
@Bean
@ConditionalOnMissingBean
public EmbeddedAcmeService embeddedAcmeService() { ... }
}
}
如果在元注解中使用 @ConditionalOnClass 或 @ConditionalOnMissingClass 来组成自己的组合注解,
则在不处理这种情况下,必须使用 name 来引用该类。
|
Bean条件
@ConditionalOnBean
和 @ConditionalOnMissingBean
注解允许根据是否存在特定bean来包含bean。
你可以使用 value
属性按类型指定bean或使用 name
属性按名称指定bean。
search
属性使你可以限制在搜索bean时应考虑的 ApplicationContext
层次结构。
当放置在 @Bean
方法上时,目标类型默认为该方法的返回类型,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }
}
在前面的示例中,如果 ApplicationContext
中没有包含 MyService
类型的bean,将创建 myService
bean。
你要特别注意添加bean定义的顺序,因为这些条件是根据到目前为止已处理的内容来评估的。
出于这个原因,我们建议在自动配置类上仅使用 @ConditionalOnBean 和 @ConditionalOnMissingBean 注解
(因为可以保证在添加任何用户定义的bean定义后加载它们)。
|
@ConditionalOnBean 和 @ConditionalOnMissingBean 不会阻止创建 @Configuration 类。
在类级别使用这些条件与使用注解标记每个包含的 @Bean 方法之间的唯一区别是,如果条件不匹配,则前者会阻止将 @Configuration 类注册为bean。
|
Property条件
@ConditionalOnProperty
注解允许基于Spring Environment
属性包含的配置,使用 prefix
和 name
属性指定应检查的属性。
默认情况下,将匹配存在且不等于 false
的任何属性。你也可以使用 havingValue
和 matchIfMissing
属性来创建更高级的检查。
Resource条件
@ConditionalOnResource
注解仅在存在特定资源时才包含配置。可以使用常规的Spring约定来指定资源,
如以下示例所示:file:/home/user/test.dat
。
Web应用条件
@ConditionalOnWebApplication
和 @ConditionalOnNotWebApplication
注解允许根据应用程序是否为“Web应用程序”来包含配置。
基于Servlet的Web应用程序是使用Spring WebApplicationContext
,定义 session
作用域或具有 ConfigurableWebEnvironment
的任何应用程序。
响应式Web应用程序是使用 ReactiveWebApplicationContext
或具有 ConfigurableReactiveWebEnvironment
的任何应用程序。
SpEL表达式条件
@ConditionalOnExpression
注解允许基于 SpEL表达式的结果来包含配置。
2.28.4. 测试你的自动配置
自动配置可能受许多因素影响:用户配置(@Bean
定义和 Environment
自定义),条件评估(存在特定库)以及其他因素。
具体而言,每个测试都应创建定义良好的 ApplicationContext
,以表示这些自定义项的组合。
ApplicationContextRunner
提供了一种实现此目标的好方法。
通常将 ApplicationContextRunner
定义为测试类的字段,以收集基本的通用配置。
下面的示例确保始终调用 UserServiceAutoConfiguration
:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));
如果必须定义多个自动配置,则无需按照与运行应用程序时完全相同的顺序调用它们的声明。 |
每个测试都可以使用运行器来表示特定的用例。例如:下面的示例调用一个用户配置(UserConfiguration
)并检查自动配置是否正确退出。
调用 run
提供了可与 Assert4J
一起使用的回调上下文。
@Test
void defaultServiceBacksOff() {
this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context).getBean("myUserService").isSameAs(context.getBean(UserService.class));
});
}
@Configuration(proxyBeanMethods = false)
static class UserConfiguration {
@Bean
UserService myUserService() {
return new UserService("mine");
}
}
也可以轻松自定义 Environment
,如以下示例所示:
@Test
void serviceNameCanBeConfigured() {
this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class).getName()).isEqualTo("test123");
});
}
运行器还可以用于显示 ConditionEvaluationReport
。
可以以 INFO
或 DEBUG
级别打印报告。以下示例显示如何使用 ConditionEvaluationReportLoggingListener
在自动配置测试中打印报告。
@Test
public void autoConfigTest {
ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withInitializer(initializer).run((context) -> {
// Do something...
});
}
模拟一个Web上下文
如果你需要测试仅在Servlet或Reactive Web应用程序上下文中运行的自动配置,请分别使用
WebApplicationContextRunner
或 ReactiveWebApplicationContextRunner
。
覆盖类路径
还可以测试在运行时不存在特定的类和/或程序包时发生的情况。
Spring Boot附带有 FilteredClassLoader
,运行器可以轻松使用。
在以下示例中,我们断言,如果不存在 UserService
,则会自动禁用自动配置:
@Test
void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
.run((context) -> assertThat(context).doesNotHaveBean("userService"));
}
2.28.5. 创建自己的Starter
一个库的完整Spring Boot starter可能包含以下组件:
-
autoconfigure
模块:包含自动配置代码。 -
starter
模块:提供对autoconfigure
模块以及其库的依赖,和通常有用的任何其他依赖项。 简而言之,添加starter应提供开始使用该库所需的一切。
如果不需要将这两个问题分开,则可以将自动配置代码和依赖管理组合在一起。 |
命名
你应该确保为启动器提供适当的命名空间。即使你使用其他Maven groupId
,也不要以 spring-boot
开头模块名称。
将来,我们可能会为你自动配置的内容提供官方支持。
根据经验,你应该在启动器后命名一个组合模块。例如:假设你要为“acme”创建starter,
并命名自动配置模块 acme-spring-boot-autoconfigure
和启动器 acme-spring-boot-starter
。
如果只有一个模块将两者结合在一起,则将其命名为 acme-spring-boot-starter
。
配置键
如果你的starter提供了配置键,请为其使用唯一的命名空间。
特别是,不要将键包含在Spring Boot使用的名称空间中(例如:server
, management
, spring
等)。
如果使用相同的命名空间,将来我们可能会以破坏模块的方式修改这些命名空间。
根据经验,所有键都必须拥有自己的命名空间(例如:acme
)。
通过为每个属性添加字段javadoc来确保文档化配置键,如以下示例所示:
@ConfigurationProperties("acme")
public class AcmeProperties {
/**
* Whether to check the location of acme resources.
*/
private boolean checkLocation = true;
/**
* Timeout for establishing a connection to the acme server.
*/
private Duration loginTimeout = Duration.ofSeconds(3);
// getters & setters
}
你仅应将简单文本与 @ConfigurationProperties 字段Javadoc一起使用,因为在将它们添加到JSON之前不会对其进行处理。
|
这是我们内部遵循的一些规则,以确保描述一致:
-
请勿以“The”或“A”开头描述。
-
对于
boolean
类型,请以“Whether”或“Enable”开始描述。 -
对于基于集合的类型,请以“Comma-separated list”开始描述。
-
使用
java.time.Duration
而不是long
,如果它不为毫秒,请描述默认单位,例如:“If a duration suffix is not specified, seconds will be used”。 -
除非必须在运行时确定默认值,否则请不要在描述中提供默认值。
确保触发元数据生成,
以便IDE助手也可用于你的键。你可能需要查看生成的元数据(META-INF/spring-configuration-metadata.json
),
以确保正确记录了你的键。在兼容的IDE中使用自己的starter也是验证元数据质量的好主意。
autoconfigure
模块
autoconfigure
模块包含开始使用该库所需的所有内容。它还可能包含配置键定义(例如:@ConfigurationProperties
)
和可用于进一步自定义组件初始化方式的任何回调接口。
你应该将对库的依赖项标记为optional,以便可以更轻松地在项目中包括 autoconfigure 模块。
如果这样做,则不提供该库,并且默认情况下,Spring Boot会回退。
|
Spring Boot使用注解处理器来收集元数据文件(META-INF/spring-autoconfigure-metadata.properties
)中自动配置的条件。
如果存在该文件,它将用于急切过滤不匹配的自动配置,这将缩短启动时间。建议在包含自动配置的模块中添加以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
对于Gradle 4.5及更早版本,应在配置中使用 compileOnly
声明依赖项,如以下示例所示:
dependencies {
compileOnly "org.springframework.boot:spring-boot-autoconfigure-processor"
}
对于Gradle 4.6和更高版本,应在配置中使用 annotationProcessor
声明依赖项,如以下示例所示:
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
}
starter模块
Starter确实是一个空jar。其唯一目的是提供必要的依赖关系以使用库。你可以将其视为对入门所需。
不要对添加了启动器的项目做任何假设。如果你要自动配置的库通常需要其他启动器,请同时提及它们。 如果可选依赖项的数量很高,则提供一组适当的 默认 依赖项可能会很困难,因此你应该避免包括对于库的典型用法不必要的依赖项。 换句话说,你不应包括可选的依赖项。
无论哪种方式,你的starter都必须直接或间接引用(即如果你的starter依赖于另一个starter,则无需添加它)
核心Spring Boot starter(spring-boot-starter )。如果仅使用你的自定义starter创建项目,
则会通过使用该核心starter来支持Spring Boot的核心功能。
|
2.29. 接下来要读什么
如果你想了解有关本节中讨论的任何类的更多信息,可以查看 Spring Boot API文档或 直接浏览源代码。
如果你有特定问题,请查看 how-to部分。
如果你对Spring Boot的核心功能感到满意,则可以继续阅读有关 生产就绪功能的信息。
3. Spring Boot Actuator: 生产就绪功能
Spring Boot包含许多其他功能,可帮助你在将应用程序投入生产时监控和管理你的应用程序。 你可以选择使用HTTP端点或JMX管理和监视你的应用程序。审计,健康状况和指标收集也可以自动应用于你的应用程序。
3.1. 启用生产就绪功能
spring-boot-actuator
模块提供了Spring Boot生产就绪的所有功能。
启用这些功能的最简单方法是添加 spring-boot-starter-actuator
‘Starter’ 依赖项。
要将执行器添加到基于Maven的项目中,请添加以下 ‘Starter’ 依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
对于Gradle,请使用以下声明:
dependencies {
compile("org.springframework.boot:spring-boot-starter-actuator")
}
3.2. 端点
执行器端点使你可以监视应用程序并与之交互。Spring Boot包含许多内置端点,你可以添加自己的端点。例如:health
端点提供基本的应用程序运行状况信息。
每个端点都可以启用或禁用。这控制了是否创建端点以及它的bean是否在应用程序上下文中存在。
为了可以远程访问,端点还必须通过JMX或HTTP公开。大多数应用程序选择HTTP,其中端点的ID和 /actuator
前缀被映射到一个URL。
例如,默认情况下,health
端点映射到 /actuator/health
。
可以使用以下与技术无关的端点:
ID | 描述 |
---|---|
|
公开当前应用程序的审计事件信息。需要一个 |
|
显示应用程序中所有Spring Beans的完整列表。 |
|
公开可用的缓存。 |
|
显示在配置和自动配置类上评估的条件以及它们匹配或不匹配的原因。 |
|
显示所有 |
|
公开Spring的 |
|
显示已应用的所有Flyway数据库迁移。需要一个或多个 |
|
显示应用程序运行状况信息。 |
|
显示HTTP跟踪信息(默认情况下,公开最近100个HTTP请求-响应交换)。需要一个 |
|
显示任意应用程序信息。 |
|
显示Spring Integration图。依赖于 |
|
显示和修改应用程序中日志记录器的配置。 |
|
显示已应用的所有Liquibase数据库迁移。需要一个或多个 |
|
显示当前应用程序的度量指标信息。 |
|
显示整理的所有 |
|
显示应用程序中的所有计划任务。 |
|
允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。 |
|
使应用程序正常关闭。默认禁用。 |
|
执行线程转储。 |
如果你的应用程序是Web应用程序(Spring MVC,Spring WebFlux或Jersey),则可以使用以下附加端点:
ID | 描述 |
---|---|
|
返回一个 |
|
通过HTTP公开JMX bean(当Jolokia在类路径上时,不适用于WebFlux)。需要依赖于 |
|
返回日志文件的内容(如果已设置 |
|
以Prometheus服务器可以抓取的格式公开指标。需要依赖于 |
3.2.1. 启用端点
默认情况下,除 shutdown
外的所有端点均处于启用状态。要配置端点的启用,请使用其 management.endpoint.<id>.enabled
属性。以下示例启用
shutdown
端点:
management.endpoint.shutdown.enabled=true
如果你希望端点支持选择加入而不是选择退出,请将 management.endpoints.enabled-by-default
属性设置为 false
并使用单个端点的 enabled
属性重新启用。
以下示例仅启用 info
端点并禁用所有其他端点:
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
禁用的端点将从应用程序上下文中完全删除。如果只想更改公开端点的技术,请改用include 和 exclude 属性。
|
3.2.2. 暴露端点
由于端点可能包含敏感信息,因此应谨慎考虑何时公开它们。下表显示了默认暴露的内置端点:
ID | JMX | Web |
---|---|---|
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
Yes |
|
N/A |
No |
|
Yes |
No |
|
Yes |
Yes |
|
Yes |
No |
|
N/A |
No |
|
N/A |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
N/A |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
|
Yes |
No |
要更改暴露哪些端点,请使用以下特定于技术的 include
和 exclude
属性:
属性 | 默认值 |
---|---|
|
|
|
|
|
|
|
|
include
属性列出了公开的端点的ID。
exclude
属性列出了不应公开的端点的ID。
exclude
属性优先于 include
属性。
include
和 exclude
属性都可以使用端点ID列表进行配置。
例如,要停止通过JMX公开所有端点,而仅公开 health
和 info
端点,请使用以下属性:
management.endpoints.jmx.exposure.include=health,info
*
可用于选择所有端点。
例如,要通过HTTP公开除 env
和 bean
端点之外的所有端点,请使用以下属性:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
|
如果你的应用程序是公开的,我们强烈建议你保护端点。 |
如果你想在端点暴露时实现自己的策略,则可以注册 EndpointFilter bean。
|
3.2.3. 保护HTTP端点
你应该像对待其他任何敏感URL一样,小心保护HTTP端点的安全。
如果存在Spring Security,则默认情况下将使用Spring Security的内容协商策略保护端点的安全。
例如,如果你希望为HTTP端点配置自定义安全性,只允许具有特定角色的用户访问它们,
Spring Boot提供了一些方便的 RequestMatcher
对象,可以将它们与Spring Security结合使用。
典型的Spring Security配置可能类似于以下示例:
@Configuration(proxyBeanMethods = false)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
http.httpBasic();
}
}
前面的示例使用 EndpointRequest.toAnyEndpoint()
将请求匹配到任何端点,然后确保所有端点具有 ENDPOINT_ADMIN
角色才可访问。
EndpointRequest
还提供了其他几种匹配器方法。有关详细信息,请参见API文档(
HTML 或
PDF)。
如果将应用程序部署在防火墙后面,则可能希望无需进行身份验证即可访问所有执行器端点。
你可以通过更改 management.endpoints.web.exposure.include
属性来做到这一点,如下所示:
management.endpoints.web.exposure.include=*
此外,如果存在Spring Security,则需要添加自定义安全配置,该配置允许未经身份验证的端点访问,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
requests.anyRequest().permitAll());
}
}
3.2.4. 配置端点
端点自动缓存不带任何参数的读取操作的响应。要配置端点缓存响应的时间,请使用其 cache.time-to-live
属性。
以下示例将 beans
端点的缓存的生存时间设置为10秒:
management.endpoint.beans.cache.time-to-live=10s
前缀 management.endpoint.<name> 用于唯一标识正在配置的端点。
|
发出经过身份验证的HTTP请求时,将 Principal 视为端点的输入,因此不会缓存响应。
|
3.2.5. 用于执行器Web端点的超媒体
添加了“发现页面”,其中包含指向所有端点的链接。默认情况下,在 /actuator
上提供“发现页面”。
配置自定义管理上下文路径后,“发现页面”会自动从 /actuator
移至管理上下文的根目录。例如,如果管理上下文路径为 /management
,则可以从
/management
访问发现页面。当管理上下文路径设置为 /
时,将禁用发现页面,以防止与其他映射发生冲突的可能性。
3.2.6. CORS支持
跨域资源共享 (CORS) 是 W3C 规范,使你可以灵活地指定授权哪种类型的跨域请求。 如果你使用Spring MVC或Spring WebFlux,则可以将Actuator的Web端点配置为支持这种情况。
默认情况下,CORS支持是禁用的,并且仅在设置了 management.endpoints.web.cors.allowed-origins
属性后才启用。
以下配置允许来自 example.com
域的 GET
和 POST
调用:
management.endpoints.web.cors.allowed-origins=https://example.com
management.endpoints.web.cors.allowed-methods=GET,POST
有关选项的完整列表,请参见 CorsEndpointProperties。 |
3.2.7. 实现自定义端点
如果添加带 @Endpoint
注解的 @Bean
,则带 @ReadOperation
,@WriteOperation
或 @DeleteOperation
注解的任何方法都将通过JMX以及Web应用程序通过HTTP自动公开。
可以使用Jersey,Spring MVC或Spring WebFlux通过HTTP公开端点。如果同时提供Jersey和Spring MVC,将使用Spring MVC。
你也可以使用 @JmxEndpoint
或 @WebEndpoint
编写特定于技术的端点。这些端点仅限于各自的技术。例如,@WebEndpoint
仅通过HTTP公开,而不通过JMX公开。
你可以使用 @EndpointWebExtension
和 @EndpointJmxExtension
编写特定于技术的扩展。这些注解使你可以提供特定于技术的操作来扩展现有端点。
最后,如果你需要访问特定于Web框架的功能,则可以实现Servlet或Spring @Controller
和 @RestController
端点,但代价是它们在JMX上不可用,或者在使用其他web框架时不可用。
接收输入
端点上的操作通过其参数接收输入。通过网络公开时,这些参数的值取自URL的查询参数和JSON请求正文。
通过JMX公开时,参数将映射到MBean操作的参数。默认情况下,参数是必需的。
可以通过使用 @org.springframework.lang.Nullable
对其进行注释来使它们成为可选的。
JSON请求正文中的每个根属性都可以映射到端点的参数。考虑以下JSON请求正文:
{
"name": "test",
"counter": 42
}
这可用于调用采用 String name
和 int counter
参数的写操作。
由于端点与技术无关,因此只能在方法签名中指定简单类型。特别是不支持使用定义 name 和 counter 属性的自定义类型声明单个参数。
|
为了使输入映射到操作方法的参数,实现端点的Java代码应使用 -parameters 进行编译,
而实现端点的Kotlin代码应使用 -java-parameters 进行编译。如果你使用的是Spring Boot的Gradle插件,
或者使用的是Maven和 spring-boot-starter-parent ,则此操作会自动发生。
|
输入类型转换
如有必要,传递给端点操作方法的参数会自动转换为所需的类型。
在调用操作方法之前,使用 ApplicationConversionService
实例以及任何具有 @EndpointConverter
限定的
Converter
或 GenericConverter
Bean,将通过JMX或HTTP请求接收的输入转换为所需的类型。
自定义Web端点
@Endpoint
,@WebEndpoint
或 @EndpointWebExtension
上的操作会使用Jersey,Spring MVC或Spring
WebFlux通过HTTP自动公开。如果同时提供Jersey和Spring MVC,将使用Spring MVC。
Web端点请求谓词
对于在暴露于Web的端点上的每个操作,都会自动生成一个请求谓词。
路径
谓词的路径由端点的ID和暴露于Web的端点的基本路径确定。默认的基本路径是 /actuator
。
例如:具有 sessions
ID的端点将使用 /actuator/sessions
作为其谓词的路径。
通过使用 @Selector
注解操作方法的一个或多个参数,可以进一步自定义路径。这样的参数作为路径变量添加到路径谓词。
调用端点操作时,变量的值将传递到操作方法中。如果要捕获所有剩余的路径元素,可以将
@Selector(Match=ALL_REMAINING)
添加到最后一个参数,并将其设置为与 String[]
转换兼容的类型。
HTTP方法
谓词的HTTP方法由操作类型决定,如下表所示:
操作 |
---|
HTTP方法 |
|
|
|
|
|
|
消费
对于使用请求体的 @WriteOperation
(HTTP POST
),谓词的消费类型为
application/vnd.spring-boot.actuator.v2+json, application/json
。对于所有其他操作,消费类型为空。
生产
谓词的生产类型可以通过 @DeleteOperation
,@ReadOperation
和 @WriteOperation
注解的 produces
属性来确定。
该属性是可选的。如果未使用,则会自动确定生产类型。
如果操作方法返回 void
或 Void
,则生产类型为空。如果操作方法返回 org.springframework.core.io.Resource
,
则生产类型为 application/octet-stream
。对于所有其他操作,生产类型为
application/vnd.spring-boot.actuator.v2+json, application/json
。
Web端点响应状态
端点操作的默认响应状态取决于操作类型(读,写或删除)以及该操作返回的内容(如果有)。
@ReadOperation
返回一个值,响应状态将为 200 (OK)。如果未返回值,则响应状态将为 404 (Not Found)。
如果 @WriteOperation
或 @DeleteOperation
返回一个值,则响应状态将为 200 (OK)。如果未返回值,则响应状态将为 204 (No Content)。
如果在没有必需参数或无法将参数转换为必需类型的参数的情况下调用操作,则不会调用该操作方法,并且响应状态将为 400 (Bad Request)。
Web端点范围请求
HTTP Range请求可用于请求HTTP资源的一部分。使用Spring MVC或Spring Web Flux时,返回 org.springframework.core.io.Resource
的操作会自动支持范围请求。
使用Jersey时,范围请求不受支持。 |
Web端点安全
Web端点或Web特定端点扩展上的操作可以接收当前的 java.security.Principal
或
org.springframework.boot.actuate.endpoint.SecurityContext
作为方法参数。
前者通常与 @Nullable
结合使用,以为经过身份验证和未经身份验证的用户提供不同的行为。
后者通常用于使用其 isUserInRole(String)
方法执行授权检查。
Servlet端点
通过实现带有 @ServletEndpoint
注解的类(也可以实现 Supplier<EndpointServlet>
),可以将Servlet公开为端点。
Servlet端点提供了与Servlet容器更深层次的集成,但以牺牲可移植性为代价。它们用于将现有Servlet公开为端点。
对于新的端点,尽可能使用 @Endpoint
和 @WebEndpoint
注解。
控制器端点
@ControllerEndpoint
和 @RestControllerEndpoint
可用于实现仅由Spring MVC或Spring WebFlux公开的端点。
使用Spring MVC和Spring WebFlux的标准注解(例如: @RequestMapping
和 @GetMapping
)映射方法,并将端点的ID用作路径的前缀。
控制器端点提供了与Spring Web框架更深层次的集成,但以牺牲可移植性为代价。尽可能使用 @Endpoint
和 @WebEndpoint
注解。
3.2.8. 健康信息
你可以使用运行状况信息来检查正在运行的应用程序的状态。监视软件通常使用它在生产系统出现故障时向某人发出警报。
health
端点公开的信息取决于 management.endpoint.health.show-details
和
management.endpoint.health.show-components
属性,可以使用以下值之一配置属性:
名称 |
---|
描述 |
|
详细信息永远不会显示。 |
|
详细信息仅显示给授权用户。可以使用 |
|
向所有用户显示详细信息。 |
默认值为 never
。当用户担任端点的一个或多个角色时,该用户被视为已授权。如果端点没有配置的角色(默认值),
则所有通过身份验证的用户均被视为已授权。可以使用 management.endpoint.health.roles
属性配置角色。
如果你已保护应用程序安全并希望使用 always ,则安全配置必须允许经过身份验证的用户和未经身份验证的用户都可以访问运行状况端点。
|
运行状况信息是从 HealthContributorRegistry
的内容(默认情况下,在 ApplicationContext
中定义的所有 HealthContributor
实例)中收集的。
Spring Boot包括许多自动配置的 HealthContributor
,你也可以编写自己的 HealthContributor
。
HealthContributor
可以是 HealthIndicator
或 CompositeHealthContributor
。HealthIndicator
提供实际的健康信息,包括 Status
。
CompositeHealthContributor
提供了其他 HealthContributor
的组合。所有贡献者合起来形成一个树形结构来代表整个系统的健康状况。
默认情况下,最终的系统运行状况是由 StatusAggregator
派生的,StatusAggregator
根据状态的有序列表对每个 HealthIndicator
的状态进行排序。
排序列表中的第一个状态用作整体健康状态。如果没有 HealthIndicator
返回 StatusAggregator
已知的状态,则使用 UNKNOWN
状态。
HealthContributorRegistry 可用于在运行时注册和注销健康指标。
|
自动配置的HealthIndicators
适当时,Spring Boot会自动配置以下 HealthIndicators
:
名称 | 描述 |
---|---|
检查Cassandra数据库是否已启动。 |
|
检查Couchbase集群是否已启动。 |
|
检查磁盘空间不足。 |
|
检查Elasticsearch集群是否已启动。 |
|
检查Hazelcast服务器是否已启动。 |
|
检查InfluxDB服务器是否已启动。 |
|
检查JMS代理是否启动。 |
|
检查LDAP服务器是否已启动。 |
|
检查邮件服务器是否已启动。 |
|
检查Mongo数据库是否已启动。 |
|
检查Neo4j数据库是否已启动。 |
|
始终以 |
|
检查Rabbit服务器是否已启动。 |
|
检查Redis服务器是否启动。 |
|
检查Solr服务器是否已启动。 |
你可以通过设置 management.health.defaults.enabled 属性来禁用它们。
|
编写自定义健康指标
为了提供自定义的健康信息,你可以注册实现 HealthIndicator
接口的Spring bean。
你需要提供 health()
方法的实现并返回 Health
响应。Health
响应应包括状态,并且可以选择包括要显示的其他详细信息。
以下代码显示了示例 HealthIndicator
实现:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
}
给定 HealthIndicator 的标识符是不带有 HealthIndicator 后缀(如果存在)的bean的名称。在前面的示例中,健康信息在名为 my 的条目中可用。
|
除了Spring Boot的预定义 Status
类型外,
Health
还可以返回代表新系统状态的自定义 Status
。
在这种情况下,还需要提供 StatusAggregator
接口的自定义实现,
或者必须使用 management.endpoint.health.status.order
配置属性来配置默认实现。
例如,假设在你的 HealthIndicator
实现之一中使用了代码为 FATAL
的新 Status
。要配置严重性顺序,请将以下属性添加到你的应用程序属性中:
management.endpoint.health.status.order=fatal,down,out-of-service,unknown,up
响应中的HTTP状态码反映了总体健康状态(例如:UP
映射为200,而 OUT_OF_SERVICE
和 DOWN
映射为503)。
如果通过HTTP访问health端点,则可能还需要注册自定义状态映射。例如,以下属性将 FATAL
映射到503 (service unavailable):
management.endpoint.health.status.http-mapping.fatal=503
如果需要更多控制,则可以定义自己的 HttpCodeStatusMapper bean。
|
下表显示了内置状态的默认HTTP状态映射:
状态 | 映射 |
---|---|
DOWN |
SERVICE_UNAVAILABLE (503) |
OUT_OF_SERVICE |
SERVICE_UNAVAILABLE (503) |
UP |
默认情况下没有映射,因此http状态为200 |
UNKNOWN |
默认情况下没有映射,因此http状态为200 |
Reactive健康指标
对于诸如使用Spring WebFlux的响应式应用程序,ReactiveHealthContributor
提供了一个非阻塞契约来获取应用程序的运行状况。
与传统的 HealthContributor
相似,健康信息是从 ReactiveHealthContributorRegistry
(默认情况下,在 ApplicationContext
中定义的所有 HealthContributor
和
ReactiveHealthContributor
实例)的内容中收集的。
不检查reactive API的常规 HealthContributor
在弹性调度器上执行。
在响应式应用程序中,ReactiveHealthContributorRegistry 可用于在运行时注册和注销健康指标。
|
为了从响应式API提供自定义健康信息,你可以注册实现 ReactiveHealthIndicator
接口的Spring bean。以下代码显示了示例 ReactiveHealthIndicator
实现:
@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {
@Override
public Mono<Health> health() {
return doHealthCheck() //perform some specific health check that returns a Mono<Health>
.onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build()));
}
}
要自动处理错误,请考虑继承自 AbstractReactiveHealthIndicator 。
|
自动配置的ReactiveHealthIndicators
适当时,Spring Boot会自动配置以下 ReactiveHealthIndicators
:
名称 | 描述 |
---|---|
检查Cassandra数据库是否已启动。 |
|
检查Couchbase集群是否已启动。 |
|
检查Mongo数据库是否已启动。 |
|
检查Redis服务器是否启动。 |
如有必要,可用reactive指示器代替常规指示器。另外,任何未明确处理的 HealthIndicator 都会自动包装。
|
健康组
有时候,将健康指标分为不同的组很有用。例如,如果将应用程序部署到Kubernetes,则可能需要一组不同的运行状况指示器来进行 “liveness” 和 “readiness” 探针。
要创建运行状况指示器组,可以使用 management.endpoint.health.group.<name>
属性,
并指定要 include
或 exclude
的运行状况指示器ID的列表。例如,要创建仅包含数据库指示符的组,可以定义以下内容:
management.endpoint.health.group.custom.include=db
然后,你可以通过单击 http://localhost:8080/actuator/health/custom
来检查结果。
默认情况下,组将继承与系统运行状况相同的 StatusAggregator
和 HttpCodeStatusMapper
设置,
但是,这些设置也可以基于每个组进行定义。如果需要,也可以覆盖 show-details
和 role
属性:
management.endpoint.health.group.custom.show-details=when-authorized
management.endpoint.health.group.custom.roles=admin
management.endpoint.health.group.custom.status.order=fatal,up
management.endpoint.health.group.custom.status.http-mapping.fatal=500
如果需要注册自定义 StatusAggregator 或 HttpCodeStatusMapper Bean以便与该组一起使用,则可以使用 @Qualifier("groupname") 。
|
3.2.9. 应用信息
应用程序信息公开了从 ApplicationContext
中定义的所有 InfoContributor
Bean收集的各种信息。Spring
Boot包含许多自动配置的 InfoContributor
Bean,你可以编写自己的bean。
自动配置的InfoContributors
适当时,Spring Boot会自动配置以下 InfoContributor
Bean:
名称 | 描述 |
---|---|
在 |
|
如果 |
|
如果 |
通过设置 management.info.defaults.enabled 属性,可以全部禁用它们。
|
自定义应用信息
你可以通过设置 info.*
Spring属性来自定义 info
端点公开的数据。
info
键下的所有 Environment
属性将自动显示。例如,你可以将以下设置添加到 application.properties
文件:
info.app.encoding=UTF-8
info.app.java.source=1.8
info.app.java.target=1.8
除了对这些值进行硬编码之外,你还可以 在构建时展开信息属性。 假设你使用Maven,则可以按如下所示重写前面的示例:
|
Git提交信息
info
端点的另一个有用的功能是它能够在项目构建时发布有关 git
源代码存储库状态的信息。如果有 GitProperties
Bean,
则将公开 git.branch
,git.commit.id
和 git.commit.time
属性。
如果 git.properties 文件在类路径的根目录下可用,则会自动配置 GitProperties bean。有关更多详细信息,请参见
生成git信息。
|
如果要显示完整的git信息(即 git.properties
的完整内容),请使用 management.info.git.mode
属性,如下所示:
management.info.git.mode=full
构建信息
如果有 BuildProperties
Bean,则 info
端点也可以发布有关你的构建的信息。如果在类路径中有 META-INF/build-info.properties
文件,则会发生这种情况。
Maven和Gradle插件都可以生成该文件。有关更多详细信息,请参见 生成构建信息。 |
编写自定义InfoContributors
为了提供自定义的应用程序信息,你可以注册实现 InfoContributor
接口的Spring bean。
以下示例使用单个值提供 example
条目:
import java.util.Collections;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class ExampleInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("example",
Collections.singletonMap("key", "value"));
}
}
如果请求 info
端点,则应该看到包含以下附加条目的响应:
{
"example": {
"key" : "value"
}
}
3.3. 通过HTTP进行监视和管理
如果你正在开发Web应用程序,则Spring Boot Actuator会自动配置所有启用的端点以通过HTTP公开。
默认约定是使用带有 /actuator
前缀的端点的ID作为URL路径。例如:health
公开为 /actuator/health
。
Spring MVC,Spring WebFlux和Jersey本身支持Actuator。如果同时提供Jersey和Spring MVC,将使用Spring MVC。 |
3.3.1. 自定义管理端点路径
有时,自定义管理端点的前缀很有用。例如,你的应用程序可能已经将 /actuator
用于其他目的。你可以使用
management.endpoints.web.base-path
属性更改管理端点的前缀,如以下示例所示:
management.endpoints.web.base-path=/manage
前面的 application.properties
示例将端点从 /actuator/{id}
更改为 /manage/{id}
(例如: /manage/info
)。
除非管理端口已配置为使用其他HTTP端口公开端点,
否则 management.endpoints.web.base-path 是相对于 server.servlet.context-path 的。
如果配置了 management.server.port ,则 management.endpoints.web.base-path 相对于 management.server.servlet.context-path 。
|
如果要将端点映射到其他路径,则可以使用 management.endpoints.web.path-mapping
属性。
以下示例将 /actuator/health
重新映射到 /healthcheck
:
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck
3.3.2. 自定义管理服务器端口
对于基于云的部署,通过使用默认的HTTP端口公开管理端点是明智的选择。但是,如果你的应用程序在自己的数据中心内运行,则你可能更喜欢使用其他HTTP端口公开端点。
你可以设置 management.server.port
属性以更改HTTP端口,如以下示例所示:
management.server.port=8081
在Cloud Foundry上,默认情况下,应用程序仅在端口8080上接收HTTP和TCP路由请求。 如果要在Cloud Foundry上使用自定义管理端口,则需要明确设置应用程序的路由,以将流量转发到自定义端口。 |
3.3.3. 配置特定于管理的SSL
当配置为使用定制端口时,还可以通过使用各种 management.server.ssl.*
属性将管理服务器配置为其自身的SSL。
例如,这样做可以使管理服务器通过HTTP可用,而主应用程序使用HTTPS,如以下属性设置所示:
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:store.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=false
或者,主服务器和管理服务器都可以使用SSL,但具有不同的密钥库,如下所示:
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:main.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=true
management.server.ssl.key-store=classpath:management.jks
management.server.ssl.key-password=secret
3.3.4. 自定义管理服务器地址
你可以通过设置 management.server.address
属性来自定义管理端点可用的地址。如果你只想在内部或面向操作的网络上侦听或仅侦听来自本地主机的连接,则这样做很有用。
仅当端口与主服务器端口不同时,你才能在其他地址上侦听。 |
以下示例 application.properties
不允许远程管理连接:
management.server.port=8081
management.server.address=127.0.0.1
3.3.5. 禁用HTTP端点
如果你不想通过HTTP公开端点,则可以将管理端口设置为 -1
,如以下示例所示:
management.server.port=-1
也可以使用 management.endpoints.web.exposure.exclude
属性来实现,如以下示例所示:
management.endpoints.web.exposure.exclude=*
3.4. 通过JMX进行监视和管理
Java管理扩展(JMX)提供了监视和管理应用程序的标准机制。默认情况下,此功能未启用,
可以通过将配置属性 spring.jmx.enabled
设置为 true
来启用。默认情况下,Spring Boot将管理端点公开为
org.springframework.boot
域下的JMX MBean。
3.4.1. 自定义MBean名称
MBean的名称通常是根据端点的ID生成的。例如,health
端点显示为 org.springframework.boot:type=Endpoint,name=Health
。
如果你的应用程序包含多个Spring ApplicationContext
,则可能会发现名称冲突。要解决此问题,可以将
spring.jmx.unique-names
属性设置为 true
,以便MBean名称始终是唯一的。
你还可以自定义暴露端点的JMX域。以下设置在 application.properties
中显示了如何这样做:
spring.jmx.unique-names=true
management.endpoints.jmx.domain=com.example.myapp
3.4.2. 禁用JMX端点
如果你不想通过JMX公开端点,则可以将 management.endpoints.jmx.exposure.exclude
属性设置为 *
,如以下示例所示:
management.endpoints.jmx.exposure.exclude=*
3.4.3. 通过HTTP将Jolokia用于JMX
Jolokia是一个JMX-HTTP桥,它提供了另一种访问JMX bean的方法。要使用Jolokia,请包括对 org.jolokia:jolokia-core
的依赖。例如,使用Maven,你将添加以下依赖项:
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
然后可以通过将 jolokia
或 *
添加到 management.endpoints.web.exposure.include
属性来暴露Jolokia端点。
然后,你可以在管理HTTP服务器上使用 /actuator/jolokia
访问它。
自定义Jolokia
Jolokia具有许多设置,这些设置通常是通过设置servlet参数进行配置的。
通过Spring Boot,你可以使用 application.properties
文件。为此,请在参数前面加上 management.endpoint.jolokia.config
。
如以下示例所示:
management.endpoint.jolokia.config.debug=true
禁用Jolokia
如果你使用Jolokia但不希望Spring Boot对其进行配置,则可将 management.endpoint.jolokia.enabled
属性设置为 false
,如下所示:
management.endpoint.jolokia.enabled=false
3.5. 日志记录器
Spring Boot Actuator可以在运行时查看和配置应用程序的日志级别。 你可以查看整个列表或单个记录器的配置,该配置由显式配置的日志记录级别以及日志记录框架为其指定的有效日志记录级别组成。 这些级别可以是以下之一:
-
TRACE
-
DEBUG
-
INFO
-
WARN
-
ERROR
-
FATAL
-
OFF
-
null
null
表示没有显式配置。
3.5.1. 配置记录器
要配置给定的记录器,请将部分实体 POST
到资源的URI中,如以下示例所示:
{
"configuredLevel": "DEBUG"
}
要“重置”日志记录器的特定级别(并使用默认配置),可以传递一个 null 值作为 configuredLevel 。
|
3.6. 指标
Spring Boot Actuator为 Micrometer提供依赖项管理和自动配置,Micrometer是一种支持多种监视系统的应用程序指标外观,包括:
3.6.1. 入门
Spring Boot自动配置组合的 MeterRegistry
,并为其在类路径上找到的每个受支持的实现向组合添加注册表。在运行时类路径中具有对
micrometer-registry-{system}
的依赖足以使Spring Boot配置注册表。
大多数注册表具有共同的特征。例如,即使Micrometer注册表实现位于类路径中,你也可以禁用特定的注册表。例如,禁用Datadog:
management.metrics.export.datadog.enabled=false
Spring Boot还会将任何自动配置的注册表添加到Metrics类的全局静态复合注册表中,除非你明确告诉它不要这么做:
management.metrics.use-global-registry=false
你可以注册任意数量的 MeterRegistryCustomizer
Bean来进一步配置注册表,例如在向注册表注册任何度量器之前应用通用标签:
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("region", "us-east-1");
}
你可以应用自定义到特定的注册表实现更具体的泛型类型:
@Bean
MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
return registry -> registry.config().namingConvention(MY_CUSTOM_CONVENTION);
}
完成该设置后,你可以将 MeterRegistry
注入组件并注册指标:
@Component
public class SampleBean {
private final Counter counter;
public SampleBean(MeterRegistry registry) {
this.counter = registry.counter("received.messages");
}
public void handleMessage(String message) {
this.counter.increment();
// handle message implementation
}
}
Spring Boot还配置了内置工具(即 MeterBinder
实现),你可以通过配置或专用注解标记来控制它们。
3.6.2. 支持的监控系统
AppOptics
默认情况下,AppOptics注册表会定期将指标推送到 https://api.appoptics.com/v1/measurements
。
要将指标导出到SaaS AppOptics,必须提供你的API令牌:
management.metrics.export.appoptics.api-token=YOUR_TOKEN
Atlas
management.metrics.export.atlas.uri=https://atlas.example.com:7101/api/v1/publish
Datadog
management.metrics.export.datadog.api-key=YOUR_KEY
你还可以更改将度量标准发送到Datadog的时间间隔:
management.metrics.export.datadog.step=30s
Dynatrace
Dynatrace注册表会定期将指标推送到配置的URI。 要将指标导出到 Dynatrace,必须提供你的API令牌,设备ID和URI:
management.metrics.export.dynatrace.api-token=YOUR_TOKEN
management.metrics.export.dynatrace.device-id=YOUR_DEVICE_ID
management.metrics.export.dynatrace.uri=YOUR_URI
你还可以更改将度量标准发送到Dynatrace的时间间隔:
management.metrics.export.dynatrace.step=30s
Elastic
默认情况下,指标会导出到在本地计算机上运行的 Elastic。 可以使用以下属性提供要使用的Elastic服务器的位置:
management.metrics.export.elastic.host=https://elastic.example.com:8086
Ganglia
默认情况下,指标将导出到在本地计算机上运行的 Ganglia。 可以使用以下命令提供要使用的 Ganglia服务器主机和端口:
management.metrics.export.ganglia.host=ganglia.example.com
management.metrics.export.ganglia.port=9649
Graphite
默认情况下,指标会导出到本地计算机上运行的 Graphite。 可以使用以下方式提供要使用的 Graphite服务器主机和端口:
management.metrics.export.graphite.host=graphite.example.com
management.metrics.export.graphite.port=9004
Micrometer提供了默认的 HierarchicalNameMapper
,用于控制如何将计量器ID 映射到平面层次结构名称。
要控制此行为,请定义 GraphiteMeterRegistry 并提供自己的 HierarchicalNameMapper 。除非你定义自己的,否则将提供自动配置的 GraphiteConfig 和 Clock Bean:
|
@Bean
public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) {
return new GraphiteMeterRegistry(config, clock, MY_HIERARCHICAL_MAPPER);
}
Humio
默认情况下,Humio注册表会定期将指标推送到 https://cloud.humio.com。 要将指标导出到SaaS Humio,必须提供你的API令牌:
management.metrics.export.humio.api-token=YOUR_TOKEN
你还应该配置一个或多个tags以标识将度量标准推送到的数据源:
management.metrics.export.humio.tags.alpha=a
management.metrics.export.humio.tags.bravo=b
Influx
management.metrics.export.influx.uri=https://influx.example.com:8086
JMX
Micrometer提供了到 JMX的层次结构映射,主要是作为一种便宜且可移植的方式在本地查看指标。
默认情况下,度量标准被导出到 metrics
JMX域。可以使用以下方式提供要使用的域:
management.metrics.export.jmx.domain=com.example.app.metrics
Micrometer提供了默认的 HierarchicalNameMapper
,用于控制如何将计量器ID 映射到平面层次结构名称。
要控制此行为,请定义 JmxMeterRegistry 并提供自己的 HierarchicalNameMapper 。除非你定义自己的,否则将提供自动配置的 JmxConfig
和 Clock Bean。
|
@Bean
public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) {
return new JmxMeterRegistry(config, clock, MY_HIERARCHICAL_MAPPER);
}
KairosDB
默认情况下,度量标准将导出到在本地计算机上运行的 KairosDB。 可以使用以下方式提供使用的 KairosDB服务器的位置:
management.metrics.export.kairos.uri=https://kairosdb.example.com:8080/api/v1/datapoints
New Relic
management.metrics.export.newrelic.api-key=YOUR_KEY
management.metrics.export.newrelic.account-id=YOUR_ACCOUNT_ID
你还可以更改将度量标准发送到New Relic的时间间隔:
management.metrics.export.newrelic.step=30s
Prometheus
Prometheus希望抓取或轮询单个应用程序实例以获取指标。
Spring Boot在 /actuator/prometheus
提供了一个执行器端点,以适当的格式显示 Prometheus scrape。
端点默认情况下不可用,若需公开,有关更多详细信息,请参见暴露端点。 |
这是添加到 prometheus.yml
的示例 scrape_config
:
scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['HOST:PORT']
对于短暂的或批处理的jobs,其时间可能不够长,无法被捕获,可以使用 Prometheus Pushgateway支持将其指标暴露给Prometheus。 要启用Prometheus Pushgateway支持,请在项目中添加以下依赖项:
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>
当在类路径上存在Prometheus Pushgateway依赖项时,Spring Boot会自动配置 PrometheusPushGatewayManager
bean。
这可以管理将指标推送到Prometheus Pushgateway。可以使用 management.metrics.export.prometheus.pushgateway
下的属性来调整 PrometheusPushGatewayManager
。对于高级配置,你还可以提供自己的 PrometheusPushGatewayManager
bean。
SignalFx
management.metrics.export.signalfx.access-token=YOUR_ACCESS_TOKEN
你还可以更改将度量标准发送到SignalFx的时间间隔:
management.metrics.export.signalfx.step=30s
Simple
Micrometer附带一个简单的内存后端,如果未配置其他注册表,该后端将自动用作后备。 这使你可以查看在metrics端点中收集了哪些指标。
使用任何其他可用后端时,内存后端都会自动禁用。你也可以显式禁用它:
management.metrics.export.simple.enabled=false
Stackdriver
Stackdriver注册表会定期将指标推送到 Stackdriver。 要将指标导出到SaaS Stackdriver,必须提供你的Google Cloud项目ID:
management.metrics.export.stackdriver.project-id=my-project
你还可以更改将度量标准发送到Stackdriver的时间间隔:
management.metrics.export.stackdriver.step=30s
StatsD
StatsD注册表急切地通过UDP将度量标准推送到StatsD agent。 默认情况下,指标会导出到本地计算机上运行的 StatsD agent。 可以使用以下方式提供要使用的StatsD agent主机和端口:
management.metrics.export.statsd.host=statsd.example.com
management.metrics.export.statsd.port=9125
你还可以更改要使用的StatsD线路协议(默认为Datadog):
management.metrics.export.statsd.flavor=etsy
Wavefront
management.metrics.export.wavefront.api-token=YOUR_API_TOKEN
或者,你可以使用在你的环境中设置的Wavefront sidecar或内部代理,将指标数据转发到Wavefront API主机:
management.metrics.export.wavefront.uri=proxy://localhost:2878
如果将指标发布到Wavefront代理(如 文档中所述),
则主机必须采用 proxy://HOST:PORT 格式。
|
你还可以更改将度量标准发送到Wavefront的时间间隔:
management.metrics.export.wavefront.step=30s
3.6.3. 支持的指标
如果适用,Spring Boot将注册以下核心指标:
-
JVM指标,报告以下各项的利用率:
-
各种内存和缓冲池
-
与垃圾收集有关的统计数据
-
线程利用率
-
加载/卸载的类数
-
-
CPU指标
-
文件描述符指标
-
Kafka消费者指标
-
Log4j2指标: 记录每个级别记录到Log4j2的事件数
-
Logback指标: 记录每个级别记录到Logback的事件数
-
Uptime指标: 报告正常运行时间的量度和代表应用程序绝对启动时间的固定量度
-
Tomcat指标 (必须将
server.tomcat.mbeanregistry.enabled
设置为true
才能注册所有Tomcat指标)
Spring MVC指标
通过自动配置,可以检测由Spring MVC处理的请求。
当 management.metrics.web.server.request.autotime.enabled
为 true
时,将对所有请求进行这种检测。
另外,当设置为 false
时,可以通过将 @Timed
添加到请求处理方法来启用检测:
@RestController
@Timed (1)
public class MyController {
@GetMapping("/api/people")
@Timed(extraTags = { "region", "us-east-1" }) (2)
@Timed(value = "all.people", longTask = true) (3)
public List<Person> listPeople() { ... }
}
1 | 控制器类,用于对控制器中的每个请求处理程序启用计时。 |
2 | 一种启用单个端点的方法。如果你将它放在类中,则不必这样做,但是可以用于进一步为此特定端点自定义计时器。 |
3 | 在 longTask = true 的方法为该方法启用长任务计时器。长任务计时器需要一个单独的度量标准名称,并且可以与短任务计时器堆叠在一起。 |
默认情况下,使用名称 http.server.requests
生成度量。
可以通过设置 management.metrics.web.server.request.metric-name
属性来自定义名称。
默认情况下,与Spring MVC相关的指标带有以下信息标签:
标签 | 描述 |
---|---|
|
处理请求时引发的任何异常的简单类名。 |
|
请求的方法(例如: |
|
请求的结果基于响应的状态码。
1xx是 |
|
响应的HTTP状态码(例如: |
|
请求在变量替换之前的URI模板,如果可能的话(例如: |
要自定义标签,请提供实现 WebMvcTagsProvider
的 @Bean
。
Spring WebFlux指标
通过自动配置,可以检测WebFlux控制器和函数式处理程序处理的所有请求。
默认情况下,度量标准的名称为 http.server.requests
。
你可以通过设置 management.metrics.web.server.request.metric-name
属性来自定义名称。
默认情况下,与WebFlux相关的指标带有以下信息标签:
标签 | 描述 |
---|---|
|
处理请求时引发的任何异常的简单类名。 |
|
请求的方法(例如: |
|
请求的结果基于响应的状态码。
1xx是 |
|
响应的HTTP状态码(例如: |
|
请求在变量替换之前的URI模板,如果可能的话(例如: |
要自定义标签,请提供实现 WebFluxTagsProvider
的 @Bean
。
Jersey服务器指标
当Micrometer的 micrometer-jersey2
模块位于类路径上时,自动配置将启用对Jersey JAX-RS实现所处理的请求的检测。
当 management.metrics.web.server.request.autotime.enabled
为 true
时,将对所有请求进行这种检测。
另外,当设置为 false
时,可以通过将 @Timed
添加到请求处理方法来启用检测:
@Component
@Path("/api/people")
@Timed (1)
public class Endpoint {
@GET
@Timed(extraTags = { "region", "us-east-1" }) (2)
@Timed(value = "all.people", longTask = true) (3)
public List<Person> listPeople() { ... }
}
1 | 在资源类上,以对资源中的每个请求处理程序启用计时。 |
2 | 关于启用单个端点的方法。如果你将它放在类中,则不必这样做,但是可以用于进一步为此特定端点自定义计时器。 |
3 | 在 longTask = true 的方法上为该方法启用长任务计时器。长任务计时器需要一个单独的度量标准名称,并且可以与短任务计时器堆叠在一起。 |
默认情况下,使用名称 http.server.requests
生成度量。
可以通过设置 management.metrics.web.server.request.metric-name
属性来自定义名称。
默认情况下,Jersey服务器指标带有以下信息:
标签 | 描述 |
---|---|
|
处理请求时引发的任何异常的简单类名。 |
|
请求的方法(例如: |
|
请求的结果基于响应的状态码。
1xx是 |
|
响应的HTTP状态码(例如: |
|
请求在变量替换之前的URI模板,如果可能的话(例如: |
要自定义标签,请提供实现 JerseyTagsProvider
的 @Bean
。
HTTP客户端指标
Spring Boot Actuator管理 RestTemplate
和 WebClient
的工具。为此,你必须注入自动配置的构建器并使用它来创建实例:
-
RestTemplateBuilder
forRestTemplate
-
WebClient.Builder
forWebClient
也可以手动应用负责此工具的定制程序,即 MetricsRestTemplateCustomizer
和 MetricsWebClientCustomizer
。
默认情况下,将使用名称 http.client.requests
生成度量。
可以通过设置 management.metrics.web.client.request.metric-name
属性来自定义名称。
默认情况下,通过检测的客户端所生成的指标带有以下信息标签:
标签 | 描述 |
---|---|
|
URI的主机部分 |
|
请求的方法(例如: |
|
请求的结果基于响应的状态码。
1xx是 |
|
响应的HTTP状态码(例如: |
|
请求在变量替换之前的URI模板,如果可能的话(例如: |
要自定义标签,可以根据你选择的客户端,提供一个实现 RestTemplateExchangeTagsProvider
或
WebClientExchangeTagsProvider
的 @Bean
。 RestTemplateExchangeTags
和 WebClientExchangeTags
中有便捷的静态函数。
缓存指标
通过自动配置,可以在启动时使用前缀为 cache
的指标来检测所有可用的 Cache
s。
高速缓存检测针对一组基本指标进行了标准化。还提供其他特定于缓存的指标。
支持以下缓存库:
-
Caffeine
-
EhCache 2
-
Hazelcast
-
任何兼容的JCache (JSR-107)实现
根据缓存的名称和从bean名称派生的 CacheManager
的名称对指标进行标记。
只有启动时可用的缓存才绑定到注册表。对于在启动阶段后即时或以编程方式创建的缓存,需要显式注册。提供 CacheMetricsRegistrar Bean可简化该过程。
|
数据源指标
通过自动配置,可以使用前缀为 jdbc.connections
的度量来检测所有可用的 DataSource
对象。
数据源检测产生的指标表示池中当前活动,空闲,最大允许和最小允许的连接。
指标还根据基于bean名称计算的 DataSource
名称进行标记。
默认情况下,Spring Boot为所有支持的数据源提供元数据。如果你喜欢的数据源不支持开箱即用,则可以添加额外的
DataSourcePoolMetadataProvider bean。有关示例,请参见 DataSourcePoolMetadataProvidersConfiguration 。
|
另外,使用Hikaricp前缀公开特定于Hikari的指标。每个度量指标都以池的名称标记(可以通过 spring.datasource.name
进行控制)。
Hibernate指标
自动配置启用所有可用的Hibernate EntityManagerFactory
实例的检测,这些实例使用名为 hibernate
的指标启用了统计信息。
指标还使用来自bean名称的 EntityManagerFactory
名称进行标记。
要启用统计信息,必须将标准JPA属性 hibernate.generate_statistics
设置为 true
。
你可以在自动配置的 EntityManagerFactory
上启用它,如以下示例所示:
spring.jpa.properties.hibernate.generate_statistics=true
RabbitMQ指标
自动配置将使用名为 rabbitmq
的指标启用所有可用的RabbitMQ连接工厂的检测。
3.6.4. 注册自定义指标
要注册自定义指标,请将 MeterRegistry
注入你的组件,如以下示例所示:
class Dictionary {
private final List<String> words = new CopyOnWriteArrayList<>();
Dictionary(MeterRegistry registry) {
registry.gaugeCollectionSize("dictionary.size", Tags.empty(), this.words);
}
// …
}
如果发现重复测量了跨组件或应用程序的一组指标,则可以将此指标封装在 MeterBinder
实现中。
默认情况下,所有 MeterBinder
Bean的指标都将自动绑定到Spring管理的 MeterRegistry
。
3.6.5. 自定义单个指标
如果需要将自定义应用于特定的 Meter
实例,则可以使用 io.micrometer.core.instrument.config.MeterFilter
接口。
默认情况下,所有 MeterFilter
bean都将自动应用于micrometer MeterRegistry.Config
。
例如,如果要将所有以 com.example
开头的计量器ID的 mytag.region
标签重命名为 mytag.area
,则可以执行以下操作:
@Bean
public MeterFilter renameRegionTagMeterFilter() {
return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
}
通用标签
通用标签通常用于在操作环境(如主机,实例,区域,堆栈等)上进行维度深入分析。通用标签适用于所有计量器,并可以按以下示例所示进行配置:
management.metrics.tags.region=us-east-1
management.metrics.tags.stack=prod
上面的示例将 region
标签和 stack
标签添加到所有计量器,其值分别为 us-east-1
和 prod
。
如果使用Graphite,则通用标签的顺序很重要。由于使用这种方法无法保证通用标签的顺序,因此建议Graphite用户定义自定义 MeterFilter 。
|
Per-meter属性
除了 MeterFilter
bean之外,还可以使用属性在per-meter基础上应用一组有限的自定义设置。
Per-meter定制适用于任何以给定名称开头的所有计量器IDs。例如,以下将禁用所有ID以 example.remote
开头的计量器:
management.metrics.enable.example.remote=false
以下属性允许按per-meter自定义:
属性 | 描述 |
---|---|
|
是否拒绝计量器发出任何指标。 |
|
是否发布适合计算可聚合(跨维度)百分比近似值的直方图。 |
|
通过限制期望值的范围来发布较少的直方图桶。 |
|
发布在应用程序中计算的百分位值 |
|
发布带有SLAs定义的桶的累积直方图。 |
有关 percentiles-histogram
,percentiles
和 sla
背后的概念的更多详细信息,请参阅micrometer文档的
直方图和百分位数部分。
3.6.6. 指标端点
Spring Boot提供了一个 metrics
端点,可用于诊断检查应用程序收集的指标。端点默认情况下不可用,若需公开,
有关更多详细信息,请参见暴露端点。
导航到 /actuator/metrics
会显示可用计量器名称的列表。你可以通过提供特定名称作为选择器来深入查看有关特定计量器的信息,
例如: /actuator/metrics/jvm.memory.max
。
你在此处使用的名称应与代码中使用的名称相匹配,而不是已经针对其附带的监视系统进行了命名约定标准化后的名称。
换句话说,如果 |
你还可以在网址末尾添加任意数量的 tag=KEY:VALUE
查询参数,以在维度上更深入地了解计量器,例如: /actuator/metrics/jvm.memory.max?tag=area:nonheap
。
报告的测量值是与计量器名称和已应用的任何标签相匹配的所有计量器的统计信息的总和。
因此,在上面的示例中,返回的“值”统计量是堆的“代码缓存”,“压缩类空间”和“元空间”区域的最大内存占用量的总和。
如果你只想查看“元空间”的最大大小,则可以添加一个额外的 |
3.7. 审计
一旦启动了Spring Security,Spring Boot Actuator将拥有一个灵活的审核框架来发布事件 (默认情况下,“身份验证成功”,“失败”和“拒绝访问”异常)。此功能对于基于身份验证失败的报告和实施锁定策略非常有用。
可以通过在应用程序的配置中提供类型为 AuditEventRepository
的bean来启用审核。为了方便起见,Spring Boot提供了一个
InMemoryAuditEventRepository
。InMemoryAuditEventRepository
具有有限的功能,我们建议仅将其用于开发环境。
对于生产环境,请考虑创建自己的替代 AuditEventRepository
实现。
3.7.1. 自定义审计
要自定义已发布的安全事件,可以提供自己的 AbstractAuthenticationAuditListener
和
AbstractAuthorizationAuditListener
的实现。
你也可以将审计服务用于自己的业务事件。
为此,可以将 AuditEventRepository
bean注入你自己的组件中并直接使用它,或者通过Spring
ApplicationEventPublisher
(通过实现 ApplicationEventPublisherAware
)发布 AuditApplicationEvent
。
3.8. HTTP追踪
可以通过在应用程序的配置中提供 HttpTraceRepository
类型的Bean来启用HTTP追踪。
为了方便起见,Spring Boot默认提供了一个 InMemoryHttpTraceRepository
,用于存储最近100次请求-响应交换的追踪。
与其他追踪解决方案相比,InMemoryHttpTraceRepository
受到限制,我们建议仅将其用于开发环境。
对于生产环境,建议使用可用于生产的追踪或可观察性解决方案,
例如:Zipkin或Spring Cloud Sleuth。或者,创建自己的 HttpTraceRepository
来满足你的需求。
httptrace
端点可用于获取有关存储在 HttpTraceRepository
中的请求-响应交换的信息。
3.8.1. 自定义HTTP追踪
要自定义每个追踪中包含的条目,请使用 management.trace.http.include
配置属性。对于高级定制,请考虑注册自己的 HttpExchangeTracer
实现。
3.9. 进程监控
在 spring-boot
模块中,你可以找到两个类来创建通常对进程监视有用的文件:
-
ApplicationPidFileWriter
创建一个包含应用程序PID的文件(默认情况下,在应用程序目录中,文件名为application.pid
)。 -
WebServerPortFileWriter
创建一个文件(一个或多个),其中包含正在运行的Web服务器的端口(默认情况下,在应用程序目录中,文件名为application.port
)。
默认情况下,这些写入器不会被激活,但你可以启用:
3.9.1. 扩展配置
在 META-INF/spring.factories
文件中,你可以激活写入PID文件的监听器,如以下示例所示:
org.springframework.context.ApplicationListener=\ org.springframework.boot.context.ApplicationPidFileWriter,\ org.springframework.boot.web.context.WebServerPortFileWriter
3.9.2. 以编程方式
你还可以通过调用 SpringApplication.addListeners(…)
方法并传递适当的
Writer
对象来激活监听器。此方法还允许你自定义 Writer
构造函数中的文件名和路径。