第5章 Spring Boot 功能

时间:2022-09-24 11:26:09

Spring Boot 功能

      本节将会介绍Spring Boot的一些细节。 在这里,您可以了解您将要使用和自定义的主要功能。 如果还没有准备好,您可能需要阅读第二部分“入门指南”和第三部分“使用 Spring Boot”部分,以使您有基础的良好基础。

23. SpringApplication

SpringApplication类提供了一种方便的方法来引导将从main()方法启动的Spring应用程序。 在许多情况下,您只需委派静态SpringApplication.run()方法:

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

当您的应用程序启动时,您应该看到类似于以下内容:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v1.5.2.RELEASE

2013-07-31 00:08:16.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)
2013-07-31 00:08:16.166 INFO 56603 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2014-03-04 13:09:54.912 INFO 41370 --- [ main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-03-04 13:09:56.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,将显示INFO 级别log消息,包括用户启动应用程序一些相关的启动细节。

23.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实现,您可以非常容易地添加自己的实现

如果没有故障分析器(analyzers)能够处理异常,您仍然可以显示完整的自动配置报告,以更好地了解出现的问题。 为此,您需要启用debug属性或启用org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer的DEBUG日志

例如,如果使用java -jar运行应用程序,则可以按如下方式启用 debug:

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

23.2 自定义Banner

可以通过在您的类路径中添加一个 banner.txt 文件,或者将banner.location设置到banner文件的位置来更改启动时打印的banner。 如果文件有一些不常用的编码,你可以设置banner.charset(默认为UTF-8)。除了文本文件,您还可以将banner.gif,banner.jpg或banner.png图像文件添加到您的类路径中,或者设置一个banner.image.location属性。 图像将被转换成ASCII艺术表现,并打印在任何文字banner上方。

您可以在banner.txt文件中使用以下占位符:

表23.1. banner变量

变量名 描述
${application.version} 在MANIFEST.MF中声明的应用程序的版本号。例如, Implementation-Version: 1.0 被打印为 1.0.
${application.formatted-version} 在MANIFEST.MF中声明的应用程序版本号的格式化显示(用括号括起来,以v为前缀)。 例如 (v1.0)。
${spring-boot.version} 您正在使用的Spring Boot版本。 例如1.5.2.RELEASE。
${spring-boot.formatted-version} 您正在使用格式化显示的Spring Boot版本(用括号括起来,以v为前缀)。 例如(v1.5.2.RELEASE)。
Ansi.NAME(or

{AnsiColor.NAME}, AnsiBackground.NAME,

{AnsiStyle.NAME}) 其中NAME是ANSI转义码的名称。 有关详细信息,请参阅 AnsiPropertySource
${application.title} 您的应用程序的标题在MANIFEST.MF中声明。 例如Implementation-Title:MyApp打印为MyApp。

如果要以编程方式生成banner,则可以使用SpringApplication.setBanner()方法。 使用org.springframework.boot.Banner 如接口,并实现自己的printBanner() 方法。

您还可以使用spring.main.banner-mode属性来决定是否必须在System.out(控制台)上打印banner,使用配置的logger(log)或不打印(off)。

23.3 定制SpringApplication

如果SpringApplication默认值不符合您的想法,您可以创建本地实例并进行自定义。 例如,关闭banner:

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。 有关详细信息,请参见第24章“外部配置”

有关配置选项的完整列表,请参阅SpringApplication Javadoc

23.4 流式构建 API

如果您需要构建一个ApplicationContext层次结构(具有父/子关系的多个上下文),或者如果您只想使用“流式(fluent)”构建器API,则可以使用SpringApplicationBuilder。

SpringApplicationBuilder允许您链式调用多个方法,并包括允许您创建层次结构的父和子方法。

例如:

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

创建ApplicationContext层次结构时有一些限制,例如 Web组件必须包含在子上下文中,并且相同的环境将用于父和子上下文。 有关详细信息,请参阅SpringApplicationBuilder Javadoc

23.5 Application events and listeners

除了常见的Spring Framework事件(如 ContextRefreshedEvent)之外,SpringApplication还会发送一些其他应用程序事件。

在创建ApplicationContext之前,实际上触发了一些事件,因此您不能在@Bean上注册一个监听器。 您可以通过SpringApplication.addListeners(…) 或SpringApplicationBuilder.listeners(…)方法注册它们。

如果您希望自动注册这些侦听器,无论创建应用程序的方式如何,都可以将META-INF / spring.factories文件添加到项目中,并使用org.springframework.context.ApplicationListener引用您的侦听器。
org.springframework.context.ApplicationListener=com.example.project.MyListener

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

  1. ApplicationStartingEvent在运行开始时发送,但在注册侦听器和注册初始化器之后。
  2. 当已经知道要使用的上下文(context)环境,并在context创建之前,将发送ApplicationEnvironmentPreparedEvent。
  3. ApplicationPreparedEvent在启动刷新(refresh)之前发送,但在加载了bean定义之后。
  4. ApplicationReadyEvent在刷新之后被发送,并且处理了任何相关的回调以指示应用程序准备好服务请求。
  5. 如果启动时发生异常,则发送ApplicationFailedEvent。

一般您不需要使用应用程序事件,但可以方便地知道它们存在。 在内部,Spring Boot使用事件来处理各种任务。

23.6 Web 环境

SpringApplication将尝试代表您创建正确类型的ApplicationContext。 默认情况下,将使用AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext,具体取决于您是否正在开发Web应用程序。

用于确定“Web环境”的算法是相当简单的(基于几个类的存在)。 如果需要覆盖默认值,可以使用setWebEnvironment(boolean webEnvironment)。

也可以通过调用setApplicationContextClass() 对ApplicationContext完全控制。

在JUnit测试中使用SpringApplication时,通常需要调用setWebEnvironment()

23.7 访问应用程序参数

如果您需要访问传递给SpringApplication.run()的应用程序参数,则可以注入org.springframework.boot.ApplicationArguments bean。 ApplicationArguments接口提供对原始String []参数以及解析选项和非选项参数的访问:

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注解注入应用程序参数。

23.8 使用ApplicationRunner或CommandLineRunner

SpringApplication启动时如果您需要运行一些特定的代码,就可以实现ApplicationRunner或CommandLineRunner接口。 两个接口都以相同的方式工作,并提供一个单独的运行方法,这将在SpringApplication.run(…)完成之前调用。

CommandLineRunner接口提供对应用程序参数的访问(简单的字符串数组),而ApplicationRunner使用上述的ApplicationArguments接口。

@Component
public class MyBean implements CommandLineRunner {

public void run(String... args) {
// Do something...
}

}

如果定义了若干CommandLineRunner或ApplicationRunner bean,这些bean必须按特定顺序调用,您可以实现org.springframework.core.Ordered接口,也可以使用org.springframework.core.annotation.Order注解。

23.9 Application exit

每个SpringApplication将注册一个JVM关闭钩子,以确保ApplicationContext在退出时正常关闭。 可以使用所有标准的Spring生命周期回调(例如DisposableBean接口或@PreDestroy注释)。

另外,如果希望在应用程序结束时返回特定的退出代码,那么bean可以实现org.springframework.boot.ExitCodeGenerator接口。

23.10 管理功能

可以通过指定spring.application.admin.enabled属性来为应用程序启用与管理相关的功能。 这会在平台MBeanServer上暴露SpringApplicationAdminMXBean。 您可以使用此功能来远程管理您的Spring Boot应用程序。 这对于任何服务包装器(service wrapper)实现也是有用的。

如果您想知道应用程序在哪个HTTP端口上运行,请使用local.server.port键获取该属性。

启用此功能时请小心,因为MBean公开了关闭应用程序的方法。

24. 外部配置

Spring Boot允许您外部化您的配置,以便您可以在不同的环境中使用相同的应用程序代码。 您可以使用properties文件,YAML文件,环境变量和命令行参数来外部化配置。 可以使用@Value注释将属性值直接注入到您的bean中,该注释可通过Spring环境(Environment)抽象访问,或通过@ConfigurationProperties绑定到结构化对象

Spring Boot使用非常特别的PropertySource命令,旨在允许合理地覆盖值。属性按以下顺序选择:

  1. 在您的HOME目录设置的Devtools全局属性(~/.spring-boot-devtools.properties)。
  2. 单元测试中的 @TestPropertySource 注解。
  3. 单元测试中的 @SpringBootTest#properties 注解属性
  4. 命令行参数。
  5. SPRING_APPLICATION_JSON 中的属性值(内嵌JSON嵌入到环境变量或系统属性中)。
  6. ServletConfig 初始化参数。
  7. ServletContext 初始化参数。
  8. 来自 java:comp/env 的JNDI属性。
  9. Java系统属性(System.getProperties())。
  10. 操作系统环境变量。
  11. RandomValuePropertySource,只有随机的属性 random.* 中。
  12. jar包外面的 Profile-specific application properties (application- {profile} .properties和YAML变体)
  13. jar包内的 Profile-specific application properties (application-{profile}.properties和YAML变体)
  14. jar包外的应用属性文件(application.properties和YAML变体)。
  15. jar包内的应用属性文件(application.properties和YAML变体)。
  16. 在@Configuration上的@PropertySource注解。
  17. 默认属性(使用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外部提供一个application.properties来覆盖 name 属性; 对于一次性测试,您可以使用特定的命令行开关启动(例如,java -jar app.jar –name=”Spring”)。

SPRING_APPLICATION_JSON属性可以在命令行中提供一个环境变量。 例如在UN*X shell中:

$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar

在本例中,您将在Spring环境中使用foo.bar = spam。 您也可以在系统变量中将JSON作为spring.application.json提供:

$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar

或命令行参数:

$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'

或作为JNDI变量 java:comp/env/spring.application.json 。

24.1 配置随机值

RandomValuePropertySource可用于注入随机值(例如,进入秘密或测试用例)。 它可以产生整数,长整数,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是任何字符和值,max是整数。 如果提供max,则值为最小值,max为最大值(独占)。

24.2 访问命令行属性

默认情况下,SpringApplication将任何命令行选项参数(以’– ‘开头,例如–server.port=9000)转换为属性,并将其添加到Spring环境中。 如上所述,命令行属性始终优先于其他属性来源。

如果不希望将命令行属性添加到环境中,可以使用SpringApplication.setAddCommandLineProperties(false)禁用它们。

24.3 应用程序属性文件

SpringApplication将从以下位置的application.properties文件中加载属性,并将它们添加到Spring Environment中:

  1. 当前目录的/config子目录
  2. 当前目录
  3. classpath中/config包
  4. classpath root路径

该列表按优先级从高到低排序。

也可以使用YAML(’.yml’)文件替代“.properties”。

如果您不喜欢application.properties作为配置文件名,可以通过指定一个spring.config.name Spring environment属性来切换到另一个。 您还可以使用spring.config.location环境属性(用逗号分隔的目录位置列表或文件路径)显式引用位置。

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

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

spring.config.name和spring.config.location一开始就被用于确定哪些文件必须被加载,因此必须将它们定义为环境属性(通常是OS env,system属性或命令行参数)。

如果spring.config.location包含的如果是目录而非文件,那么它们应该以/结尾(并将在加载之前附加从spring.config.name生成的名称,包括profile-specific的文件名)。 在spring.config.location中指定的文件按原样使用,不支持特定于配置文件的变体,并且将被任何特定于配置文件的属性覆盖。

默认的搜索路径 classpath:,classpath:/config,file:,file:config/ 始终会被搜索,不管spring.config.location的值如何。 该搜索路径从优先级排序从低到高(file:config/最高)。 如果您指定自己的位置,则它们优先于所有默认位置,并使用相同的从最低到最高优先级排序。 这样,您可以在application.properties(或使用spring.config.name选择的任何其他基础名称)中为应用程序设置默认值,并在运行时使用不同的文件覆盖它,并保留默认值。

如果您使用环境(environment)变量而不是系统属性,大多数操作系统不允许使用句点分隔(period-separated)的键名称,但可以使用下划线(例如,SPRING_CONFIG_NAME,而不是spring.config.name)

如果您运行在容器中,则可以使用JNDI属性(在 java:comp/env 中)或servlet上下文初始化参数,而不是环境变量或系统属性。

24.4 指定配置(Profile-specific)的属性

除了application.properties文件外,还可以使用命名约定application- {profile}.properties定义的指定配置文件。 环境具有一组默认配置文件,如果没有设置活动配置文件(即,如果没有显式激活配置文件,则加载了来自application-default.properties的属性)。

指定配置文件(Profile-specific)的属性从与标准application.properties相同的位置加载,指定配置( profile-specific)文件始终覆盖非指定文件,而不管指定配置文件是否在打包的jar内部或外部。

如果有几个指定配置文件,则应用最后一个配置。 例如,由spring.profiles.active属性指定的配置文件在通过SpringApplication API配置的配置之后添加,因此优先级高。

如果您在spring.config.location中指定了任何文件,则不会考虑这些特定配置(profile-specific)文件的变体。 如果您还想使用指定配置(profile-specific)文件的属性,请使用spring.config.location中的目录。

24.5 properties 文件中的占位符

application.properties中的值在使用时通过已有的环境进行过滤,以便您可以引用之前定义的值(例如,从系统属性)。

app.name=MyApp
app.description=${app.name} is a Spring Boot application

您也可以使用此技术创建现有Spring Boot属性的“简写“。 有关详细信息,请参见第72.4节“使用”短命令行参数“how-to”

24.6 使用YAML替代 Properties

YAML是JSON的超集,因此这是分层配置数据一种非常方便的格式,。 每当您的类路径中都有SnakeYAML库时,SpringApplication类将自动支持YAML作为 properties 的替代方法。

如果您使用“Starters”,SnakeYAML将通过spring-boot-starter自动提供。

24.6.1 加载 YAML

Spring Framework提供了两个方便的类,可用于加载YAML文档。 YamlPropertiesFactoryBean将YAML作为Properties加载,YamlMapFactoryBean将YAML作为Map加载。

例如,下面YAML文档:

environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App

将转化为属性:

environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App

YAML列表表示为具有[index] dereferencers的属性键,例如YAML:

my:
servers:
- dev.bar.com
- foo.bar.com

将转化为属性:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

要使用Spring DataBinder工具(@ConfigurationProperties做的)绑定到这样的属性,您需要有一个属性类型为java.util.List(或Set)的目标bean,并且您需要提供一个setter,或者 用可变值初始化它,例如 这将绑定到上面的属性

@ConfigurationProperties(prefix="my")
public class Config {

private List<String> servers = new ArrayList<String>();

public List<String> getServers() {
return this.servers;
}
}

24.6.2 将YAML作为Spring环境中的属性文件

可以使用YamlPropertySourceLoader类在Spring环境中将YAML作为PropertySource暴露出来。 这允许您使用熟悉的@Value注解和占位符语法来访问YAML属性。

24.6.3 多个YAML文件

您可以使用spring.profiles键指定单个文件中的多个特定配置文件YAML文档,以指示文档何时应用。 例如:

server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120

在上面的示例中,如果开发配置文件处于活动状态,则server.address属性将为127.0.0.1。 如果开发和生产配置文件未启用,则该属性的值将为192.168.1.100。

如果应用程序上下文启动时没有显式激活,默认配置文件将被激活。 所以在这个YAML中,我们为security.user.password设置一个仅在“默认”配置文件中可用的值:

server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak

使用“spring.profiles”元素指定的Spring profiles 以选择使用 字符。 如果为单个文档指定了否定和非否定的配置文件,则至少有一个非否定配置文件必须匹配,没有否定配置文件可能匹配。

24.6.4 YAML的缺点

YAML文件无法通过@PropertySource注解加载。 因此,在需要以这种方式加载值的情况下,需要使用properties文件。

24.6.5 合并YAML列表

如上所述,任何YAML内容最终都会转换为属性。 当通过配置文件覆盖“列表”属性时,该过程可能比较直观。

例如,假设名称和描述属性默认为空的MyPojo对象。 让我们从FooProperties中公开MyPojo的列表:

@ConfigurationProperties("foo")
public class FooProperties {

private final List<MyPojo> list = new ArrayList<>();

public List<MyPojo> getList() {
return this.list;
}

}

类比以下配置:

foo:
list:
- name: my name
description: my description
---
spring:
profiles: dev
foo:
list:
- name: my another name

如果dev配置没有激活,FooProperties.list将包含一个如上定义的MyPojo条目。 如果启用了配置文件,列表仍将包含一个条目(名称为“my another name”,description=null)。 此配置不会将第二个MyPojo实例添加到列表中,并且不会将项目合并。

当在多个配置文件中指定集合时,使用具有最高优先级的集合(并且仅使用该配置文件):

foo:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
foo:
list:
- name: my another name

在上面的示例中,考虑到dev配置文件处于激活状态,FooProperties.list将包含一个MyPojo条目(名称为“my another name”和description=null)。

24.7 类型安全的配置属性

使用@Value(“${property}”)注释来注入配置属性有时可能很麻烦,特别是如果您正在使用多个层次结构的属性或数据时。 Spring Boot提供了一种处理属性的替代方法,允许强类型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("foo")
public class FooProperties {

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定义了以下属性:

  • foo.enabled,默认为false
  • foo.remote-address,具有可以从String强转的类型
  • foo.security.username,具有内置的“安全性(security)”,其名称由属性名称决定。 特别是返回类型并没有被使用,可能是SecurityProperties
  • foo.security.password
  • foo.security.roles,一个String集合

Getters和setter方法通常是必须要有的,因为绑定是通过标准的Java Beans属性描述符,就像在Spring MVC中一样。 在某些情况下可能会省略setter方法:

  • Map 只要它们被初始化,需要一个getter,但不一定是一个setter,因为它们可以被binder修改。
  • 集合和数组可以通过索引(通常使用YAML)或使用单个逗号分隔值(Properties中)来访问。 在后一种情况下,setter方法是强制性的。 我们建议总是为这样的类型添加一个设置器。 如果您初始化集合,请确保它不是不可变的(如上例所示)
  • 如果已初始化嵌套POJO属性(如上例中的Security字段),则不需要setter方法。如果您希望binder使用其默认构造函数即时创建实例,则需要一个setter。

有些人使用Project Lombok自动添加getter和setter。 确保Lombok不会为这种类型生成任何特定的构造函数,因为构造函将被容器自动用于实例化对象。

另请参阅@Value和@ConfigurationProperties之间的不同

您还需要列出在@EnableConfigurationProperties注解中注册的属性类:

@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}

@ConfigurationProperties bean以这种方式注册时,该bean将具有常规名称:<prefix> - <fqn>,其中是@ConfigurationProperties注解中指定的环境密钥前缀,是bean的全名(fully qualified name)。 如果注解不提供任何前缀,则仅使用该bean的全名。上面示例中的bean名称将是foo-com.example.FooProperties。

即使上述配置将为FooProperties创建一个常规bean,我们建议@ConfigurationProperties仅处理环境,特别是不从上下文中注入其他bean。 话虽如此,@EnableConfigurationProperties注释也会自动应用于您的项目,以便使用@ConfigurationProperties注释的任何现有的bean都将从环境配置。 您可以通过确保FooProperties已经是一个bean来快速上面的MyConfiguration

@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {

// ... see above

}

这种配置方式与SpringApplication外部的YAML配置相当:

# application.yml

foo:
remote-address: 192.168.1.1
security:
username: foo
roles:
- USER
- ADMIN

# additional configuration as required

要使用@ConfigurationProperties bean,您可以像其他任何bean一样注入它们。

@Service
public class MyService {

private final FooProperties properties;

@Autowired
public MyService(FooProperties properties) {
this.properties = properties;
}

//...

@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}

}

使用@ConfigurationProperties还可以生成IDE可以为自己的密钥提供自动完成的元数据文件,有关详细信息,请参见附录B,配置元数据附录

24.7.1第三方配置

除了使用@ConfigurationProperties来注解类,还可以在public @Bean方法中使用它。 当您希望将属性绑定到不受控制的第三方组件时,这可能特别有用。

@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
...
}

使用 bar 前缀定义的任何属性将以与上述FooProperties示例类似的方式映射到该BarComponent bean。

24.7.2 宽松的绑定

Spring Boot使用一些宽松的规则将环境属性绑定到@ConfigurationProperties bean,因此不需要在Environment属性名称和bean属性名称之间进行完全匹配。 常用的例子是这样有用的:虚分离(例如上下文路径绑定到contextPath)和大写(例如PORT绑定到端口)环境属性。

例如,给定以下@ConfigurationProperties类:

@ConfigurationProperties(prefix="person")
public class OwnerProperties {

private String firstName;

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

}

可以使用以下属性名称:

表格 24.1. relaxed binding

Property Note
person.firstName 标准骆峰命名法。
person.first-name 虚线符号,推荐用于.properties和.yml文件。
person.first_name 下划线符号,用于.properties和.yml文件的替代格式。
PERSON_FIRST_NAME 大写格式 推荐使用系统环境变量时。

24.7.3属性转换

当Spring绑定到@ConfigurationProperties bean时,Spring将尝试将外部应用程序属性强制为正确的类型。 如果需要自定义类型转换,您可以提供ConversionService bean(使用bean id conversionService)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义转换器(使用注释为@ConfigurationPropertiesBinding的bean定义)。

由于在应用程序生命周期期间非常早请求此Bean,请确保限制ConversionService正在使用的依赖关系。 通常,您需要的任何依赖关系可能无法在创建时完全初始化。 如果配置密钥强制不需要,只需依赖使用@ConfigurationPropertiesBinding限定的自定义转换器,就可以重命名自定义ConversionService。

24.7.4 @ConfigurationProperties验证

当Spring的@Validated注释解时,Spring Boot将尝试验证@ConfigurationProperties类。 您可以直接在配置类上使用JSR-303 javax.validation约束注释。 只需确保您的类路径中符合JSR-303实现,然后在您的字段中添加约束注释:

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

@NotNull
private InetAddress remoteAddress;

// ... getters and setters

}

为了验证嵌套属性的值,您必须将关联字段注释为@Valid以触发其验证。 例如,基于上述FooProperties示例:

@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {

@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 bean的端点。 只需将您的Web浏览器指向/configprops 或使用等效的JMX端点。 请参阅生产就绪功能 细节。

24.7.5 @ConfigurationProperties 对比 @Value

@Value是核心容器功能,它不提供与类型安全配置属性相同的功能。 下表总结了@ConfigurationProperties和@Value支持的功能:

功能 @ConfigurationProperties @Value
Relaxed binding Yes No
Meta-data support Yes No
SpEL evaluation No Yes

如果您为自己的组件定义了一组配置密钥,我们建议您将其分组到使用@ConfigurationProperties注释的POJO中。 还请注意,由于@Value不支持宽松的绑定,如果您需要使用环境变量提供值,那么它不是一个很好的选择。

最后,当您可以在@Value中编写一个Spel表达式时,这些表达式不会从应用程序属性文件中处理。

25. 配置文件(Profiles)

Spring 配置文件提供了将应用程序配置隔离的方法,使其仅在某些环境中可用。 任何@Component或@Configuration都可以使用@Profile进行标记,以限制其在什么时候加载:

@Configuration
@Profile("production")
public class ProductionConfiguration {

// ...

}

一般,您可以使用spring.profiles.active Environment属性来指定哪些配置文件处于激活状态。 您可以以任何方式指定属性,例如,您可以将其包含在您的application.properties中:

spring.profiles.active=dev,hsqldb

或者使用命令行--spring.profiles.active=dev,hsqldb在命令行中指定。

25.1添加激活配置文件

spring.profiles.active属性遵循与其他属性相同的优先级规则,PropertySource最高。这意味着您可以在application.properties中指定活动配置文件,然后使用命令行开关替换它们。

有时,将特定于配置文件的属性添加到激活的配置文件而不是替换它们是有用的。 spring.profiles.include属性可用于无条件添加激活配置文件。 SpringApplication入口点还具有用于设置其他配置文件的Java API(即,在由spring.profiles.active属性激活的那些配置文件之上):请参阅setAdditionalProfiles()方法。

例如,当使用开关 -spring.profiles.active=prod 运行具有以下属性的应用程序时,proddb和prodmq配置文件也将被激活:

---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq

请记住,可以在YAML文档中定义spring.profiles属性,以确定此特定文档何时包含在配置中。 有关详细信息,请参见第72.7节“根据环境更改配置”

25.2 以编程方式设置配置文件

您可以通过在应用程序运行之前调用SpringApplication.setAdditionalProfiles(…)以编程方式设置激活配置文件。 也可以使用Spring的ConfigurableEnvironment接口激活配置文件。

25.3 配置文件指定的配置文件

通过@ConfigurationProperties引用的application.properties(或application.yml)和文件的配置文件特定变体都被视为加载文件。 有关详细信息,请参见第24.4节指定配置(Profile-specific)的属性”

26. 日志

Spring Boot使用Commons Logging进行所有内部日志记录,但使基础日志实现开放。 默认配置提供了Java Util LoggingLog4J2Logback。 在每种情况下,记录器都预先配置为使用控制台输出和可选文件输出都可用。

默认情况下,如果使用’Starters’,将会使用Logback。 还包括适当的Logback路由,以确保使用Java Util Logging,Commons Logging,Log4J或SLF4J的依赖库都能正常工作。

有很多可用于Java的日志记录框架。 如果上面的列表看起来很混乱,别担心。 一般来说,您不需要更改日志依赖关系,并且Spring Boot默认值将正常工作。

26.1 日志格式

Spring Boot的默认日志输出如下所示:

2014-03-05 10:57:51.112  INFO 45469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms
2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2014-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)

26.2 控制台输出

默认的日志配置会在控制台显示消息。 默认情况下会记录ERROR,WARN和INFO级别的消息。 您还可以通过–debug启动您的应用程序来启用“debug”模式。

$ java -jar myapp.jar --debug

您还可以在application.properties中指定debug=true。

当启用debug模式时,配置核心记录器(嵌入式容器,Hibernate和Spring Boot)的选择可以输出更多信息。 启用debug 模式不会将应用程序配置为使用DEBUG级别记录所有消息。

或者,您可以使用–trace启动应用程序(或在您的application.properties中为trace=true)启用“trace”模式。 这将为核心记录器(嵌入式容器,Hibernate模式生成和整个Spring组合)启用trace日志。

26.2.1 日志颜色输出

如果您的终端支持ANSI,颜色输出可以增加可读性。 您可以将spring.output.ansi.enabled设置为支持的值来覆盖自动检测。

使用%clr关键字配置颜色编码。 在最简单的形式下,转换器将根据日志级别对输出进行着色,例如:

%clr(%5p)

日志级别映射到颜色如下:

  • blue
  • cyan
  • faint
  • green
  • magenta
  • red
  • yellow

26.3 文件输出

默认情况下,Spring Boot将仅将日志输出到控制台,不会写到文件。 如果要将控制台上的日志输出到日志文件,则需要设置logging.file或logging.path属性(例如在application.properties中)。

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

表26.1 Logging属性

logging.file logging.path Example Description
(none) (none)   仅控制台输出
Specific file (none) my.log 写入指定的日志文件。 名称可以是确切的位置或相对于当前目录。
(none) Specific directory /var/log 将spring.log写入指定的目录。 名称可以是确切的位置或相对于当前目录。

日志文件将在10 MB时滚动输出到文件,默认情况下会记录控制台输出,ERROR,WARN和INFO级别的消息。

日志记录系统在应用程序生命周期早期初始化,并且在通过@PropertySource注解加载的属性文件中将不会找到log属性

日志属性独立于实际的日志记录基础结构。 因此,特定配置key(如Logback的logback.configurationFile)不受Spring Boot管理。

26.4 日志级别

所有支持的日志记录系统都可以在Spring Environment 中设置log级别(例如在application.properties中),使用‘logging.level.*=LEVEL’,其中’LEVEL’是TRACE,DEBUG,INFO,WARN,ERROR,FATAL, OFF之一。 可以使用logging.level.root配置根记录器。 示例application.properties:

logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

默认情况下,Spring Boot会重新启动Thymeleaf INFO消息,以便它们以DEBUG级别进行记录。 这有助于降低标准日志输出中的噪音。 有关如何在自己的配置中应用重映射的详细信息,请参阅LevelRemappingAppender

26.5 自定义日志配置

可以通过在类路径中包含适当的库来激活各种日志系统,并通过在类路径的根目录中提供合适的配置文件,或在Spring Environment属性logging.config指定的位置进一步配置。

您可以使用org.springframework.boot.logging.LoggingSystem系统属性强制Spring Boot使用特定的日志记录系统。该值应该是LoggingSystem实现的全名。 您还可以使用none值完全禁用Spring Boot的日志记录配置。

由于在创建ApplicationContext之前初始化日志,因此无法在Spring @Configuration文件中控制@PropertySources的日志记录。 系统属性和常规的Spring Boot外部配置文件工作正常。

根据您的日志记录系统,将会加载以下文件:

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

如果可能,我们建议您使用-spring变体进行日志记录配置(例如使用logback-spring.xml而不是logback.xml)。 如果使用标准配置位置,则Spring无法完全控制日志初始化。

Java Util Logging存在已知的类加载问题,从“可执行jar”运行时会导致问题。 我们建议您尽可能避免。

帮助定制一些其他属性从Spring环境转移到系统属性:

Spring Environment System Property Comments
logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 记录异常时使用的转换字。
logging.file LOG_FILE 如果定义了,则用于默认日志配置。
logging.path LOG_PATH 如果定义了,则用于默认日志配置。
logging.pattern.console CONSOLE_LOG_PATTERN 在控制台上使用的日志模式(stdout)。 (仅支持默认logback设置。)
logging.pattern.file FILE_LOG_PATTERN 在文件中使用的日志模式(如果LOG_FILE已启用)。 (仅支持默认logback设置。)
logging.pattern.level LOG_LEVEL_PATTERN 用于呈现日志级别的格式(默认%5p)。 (仅支持默认logback设置。)
PID PID 当前进程ID(如果可能的话,当未被定义为OS环境变量时被发现)。

支持的所有日志记录系统在分析其配置文件时可以查看系统属性。 有关示例,请参阅spring-boot.jar中的默认配置。

如果要在logging属性中使用占位符,则应使用Spring Boot的语法,而不是底层框架的语法。 值得注意的是,如果您使用Logback,您应该使用:作为属性名称与其默认值之间的分隔符,而不是:-

您可以通过覆盖LOG_LEVEL_PATTERN(或Logback的log.pattern.level)来添加MDC和其他ad-hoc内容到日志行。 例如,如果使用logging.pattern.level = user:%X {user}%5p,则默认日志格式将包含“user”的MDC条目(如果存在)。

2015-09-30 12:30:04.031 user:juergen INFO 22174 --- [  nio-8080-exec-0] demo.Controller
Handling authenticated request

26.6 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]]

26.6.1 指定配置文件配置

<springProfile>标签允许您根据活动的Spring配置文件可选地包含或排除配置部分。 配置文件部分支持<configuration>元素在任何位置。 使用name属性指定哪个配置文件接受配置。 可以使用逗号分隔列表指定多个配置文件。

<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>

26.6.2 环境属性

标签允许您从Spring环境中显示属性,以便在Logback中使用。 如果您在logback中访问application.properties文件中的值,这将非常有用。 标签的工作方式与Logback标准的标签类似,但不是指定直接值,而是指定属性的来源(来自Environment)。 如果需要将属性存储在本地范围以外的位置,则可以使用scope属性。 如果在环境中未设置属性的情况下需要备用值,则可以使用defaultValue属性。

<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>

RelaxedPropertyResolver用于访问Environment属性。 如果以虚线表示法(my-property-name)指定源,则将尝试所有宽松的变体(myPropertyName,MY_PROPERTY_NAME等)。

27. 开发Web应用程序

Spring Boot非常适合Web应用程序开发。 您可以使用嵌入式Tomcat,Jetty或Undertow轻松创建自包含的HTTP服务器。 大多数Web应用程序将使用spring-boot-starter-web模块快速启动和运行。

如果您尚未开发Spring Boot Web应用程序,则可以按照“Hello World!”示例进行操作。 在“入门”部分中的示例。

27.1 “Spring Web MVC框架”

Spring Web MVC框架(通常简称为“Spring MVC”)是一个丰富的“模型视图控制器”Web框架。 Spring MVC允许您创建特殊的@Controller或@RestController bean来处理传入的HTTP请求。 您的控制器中的方法将使用@RequestMapping注释映射到HTTP。

以下是@RestController用于提供JSON数据的典型示例:

@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/guide中还有几个指南可供Spring MVC使用。

27.1.1 Spring MVC自动配置

Spring Boot提供了适用于大多数应用程序的Spring MVC的自动配置。

自动配置在Spring的默认值之上添加以下功能:

  • 包含ContentNegotiatingViewResolver和BeanNameViewResolver bean。
  • 支持提供静态资源,包括对WebJars的支持(见下文)。
  • Converter,GenericConverter,Formatter beans的自动注册。
  • 支持HttpMessageConverters(见下文)。
  • 自动注册MessageCodesResolver(见下文)。
  • 静态index.html支持。
  • 自定义Favicon支持(见下文)。
  • 自动使用ConfigurableWebBindingInitializer bean(见下文)。

如果要保留Spring Boot MVC功能,并且您只需要添加其他MVC配置(interceptors, formatters, view, controllers等),你可以添加自己的WebConfigurerAdapter类型的@Configuration类,但不能使用@EnableWebMvc。 如果要提供自定义的RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver实例,您可以声明一个提供此类组件的WebMvcRegistrationsAdapter实例。

如果要完全控制Spring MVC,可以使用@EnableWebMvc添加您自己的@Configuration注释。

27.1.2 HttpMessageConverters

Spring MVC使用HttpMessageConverter接口转换HTTP请求和响应。 包括一些开箱即用的合理配置,例如对象可以自动转换为JSON(使用Jackson库)或XML(使用Jackson XML扩展,如果可用,否则使用JAXB)。 字符串默认使用UTF-8进行编码。

如果需要添加或自定义转换器,可以使用Spring Boot HttpMessageConverter类:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}

}

上下文中存在的任何HttpMessageConverter bean将被添加到转换器列表中。 您也可以以这种方式覆盖默认转换器。

27.1.3 自定义JSON序列化器和反序列化器

如果您使用Jackson序列化和反序列化JSON数据,则可能需要编写自己的JsonSerializer和JsonDeserializer类。 自定义序列化程序通常通过一个模块注册到Jackson,但是Spring Boot提供了一个备用的@JsonComponent注释,可以更容易地直接注册Spring Bean。

您可以直接在JsonSerializer或JsonDeserializer实现中使用@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还提供了JsonObjectSerializerJsonObjectDeserializer基类,它们在序列化对象时为标准的Jackson版本提供了有用的替代方法。 有关详细信息,请参阅Javadoc。

27.1.4 MessageCodesResolver

Spring MVC有一个生成错误代码的策略,用于从绑定错误中提取错误消息:MessageCodesResolver。 Spring Boot将为您创建一个错误代码,如果您设置spring.mvc.message-codes-resolver.format属性PREFIX_ERROR_CODE或POSTFIX_ERROR_CODE(请参阅DefaultMessageCodesResolver.Format中的枚举)。

27.1.5 静态内容

默认情况下,Spring Boot将从类路径或ServletContext的根目录中的名为/static(或/ public或/resources或/META-INF/resources)的目录提供静态内容。 它使用Spring MVC中的ResourceHttpRequestHandler,因此您可以通过添加自己的WebMvcConfigurerAdapter并覆盖addResourceHandlers方法来修改该行为。

在独立的Web应用程序中,来自容器的默认servlet也被启用,并且作为后备,如果Spring决定不处理它,则从ServletContext的根目录提供内容。 大多数情况下,这不会发生(除非您修改默认的MVC配置),因为Spring将始终能够通过DispatcherServlet处理请求。

默认情况下,资源映射到/ ,但可以通过spring.mvc.static-path-pattern调整。 例如,将所有资源重定位到 /resources/可以配置如下:

spring.mvc.static-path-pattern=/resources/**

您还可以使用spring.resources.static-locations(使用目录位置列表替换默认值)来自定义静态资源位置。 如果这样做,默认欢迎页面检测将切换到您的自定义位置,因此,如果在启动时任何位置都有一个index.html,它将是应用程序的主页。

除了上述“标准”静态资源位置之外,还提供了一个特殊情况,用于Webjars内容。 任何具有/ webjars / **中路径的资源都将从jar文件中提供,如果它们以Webjars格式打包。

如果您的应用程序将被打包为jar,请不要使用 src/main/webapp 目录。 虽然这个目录是一个通用的标准,但它只适用于war包,如果生成一个jar,它将被大多数构建工具忽略。

Spring Boot还支持Spring MVC提供的高级资源处理功能,允许使用例如缓存静态资源或使用Webjars的版本无关的URL。

要为Webjars使用版本无关的URL,只需添加webjars-locator依赖关系即可。然后声明您的Webjar,以jQuery为例,如“/webjars/jquery/dist/jquery.min.js”,这将产生“/webjars/jquery/xyz/dist/jquery.min.js”,其中xyz是Webjar版本 。

如果您使用JBoss,则需要声明webjars-locator-jboss-vfs依赖关系而不是webjars-locator; 否则所有Webjars都将解析为404。

要使用缓存清除功能,以下配置将为所有静态资源配置缓存清除解决方案,从而有效地在URL中添加内容哈希值,例如:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

链接资源在运行时在模板中被重写,这归功于自动配置为Thymeleaf和FreeMarker的ResourceUrlEncodingFilter。 使用JSP时,应手动声明此过滤器。 其他模板引擎现在不会自动支持,但可以使用自定义模板宏/帮助程序和使用ResourceUrlProvider

当使用例如JavaScript模块加载器动态加载资源时,重命名文件不是一个选项。这就是为什么其他策略也得到支持并可以合并的原因。 “固定(fixed)”策略将在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”,而其他资源仍将使用内容。

有关更多支持的选项,请参阅ResourceProperties

此功能已在专门的博客文章和Spring Framework参考文档中进行了详细描述。

27.1.6 自定义图标

Spring Boot在配置的静态内容位置和类路径的根目录(按顺序)中查找favicon.ico。 如果文件存在,它将被自动用作应用程序的图标。

27.1.7 ConfigurableWebBindingInitializer

Spring MVC使用WebBindingInitializer为特定请求初始化WebDataBinder。 如果您用@Bean创建自己的ConfigurableWebBindingInitializer @Bean,Spring Boot将自动配置Spring MVC以使用它。

27.1.8 模板引擎

除了REST Web服务,您还可以使用Spring MVC来提供动态HTML内容。 Spring MVC支持各种模板技术,包括Thymeleaf,FreeMarker和JSP。 许多其他模板引擎也运行自己的Spring MVC集成。

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

如果可能,应避免使用JSP,当使用嵌入式servlet容器时,JSP有几个已知的限制

当您使用默认配置的模板引擎之一时,您的模板将从 src/main/resources/templates 自动获取。

IntelliJ IDEA根据运行应用程序的方式对类路径进行不同的排序。 通过main方法在IDE中运行应用程序将导致使用Maven或Gradle打包的jar运行应用程序时的不同顺序。这可能会导致Spring Boot找不到类路径上的模板。 如果您受此问题的影响,您可以重新排序IDE中的类路径,以放置模块的类和资源。 或者,您可以配置模板前缀以搜索类路径上的每个模板目录:classpath*:/templates/

27.1.9 错误处理

默认情况下,Spring Boot提供 /error 映射,以合理的方式处理所有错误,并在servlet容器中注册为“global”错误页面。 对于机器客户端,它将产生JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。 对于浏览器客户端,有一个’whitelabel’错误视图,以HTML格式呈现相同的数据(定制它只需添加一个解析“error”的视图)。 要完全替换默认行为,您可以实现ErrorController并注册该类型的bean定义,或者简单地添加一个类型为ErrorAttributes的bean来使用现有机制,但只是替换内容。

BasicErrorController可以用作自定义ErrorController的基类。 如果要添加新内容类型的处理程序(默认情况下是专门处理text/html并为其他内容提供备选),这一点尤其有用。 要做到这一点,只需扩展BasicErrorController并添加一个带有@RequestMapping的公共方法,并创建一个新类型的bean。

您还可以定义一个@ControllerAdvice来自定义为特定控制器 and/or 异常类型返回的JSON文档。

@ControllerAdvice(basePackageClasses = FooController.class)
public class FooControllerAdvice 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);
}

}

在上面的示例中,如果由FooController在同一个包中定义的控件抛出了YourException,则将使用CustomerErrorType 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.ftl
+- <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"));
}

}

N.B. 如果您注册一个最终由Filter过滤的路径的ErrorPage(例如,像一些非Spring Web框架,例如Jersey和Wicket一样),则必须将Filter显式注册为ERROR dispatcher,例如。

@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}

(默认的FilterRegistrationBean不包括ERROR dispatcher 类型)。

WebSphere Application Server上的错误处理

当部署到servlet容器时,Spring Boot会使用其错误页面过滤器将具有错误状态的请求转发到相应的错误页面。 如果响应尚未提交,则该请求只能转发到正确的错误页面。 默认情况下,WebSphere Application Server 8.0及更高版本在成功完成servlet的服务方法后提交响应。 您应该通过将com.ibm.ws.webcontainer.invokeFlushAfterService设置为false来禁用此行为

27.1.10 Spring HATEOAS

如果您正在开发一种利用超媒体的RESTful API,Spring Boot可以为Spring HATEOAS提供自动配置,适用于大多数应用程序。 自动配置取代了使用@EnableHypermediaSupport的需求,并注册了一些Bean,以便轻松构建基于超媒体的应用程序,包括LinkDiscoverers(用于客户端支持)和配置为将响应正确地组织到所需表示中的ObjectMapper。 ObjectMapper将根据spring.jackson。*属性或Jackson2ObjectMapperBuilder bean(如果存在)进行自定义。

您可以使用@EnableHypermediaSupport控制Spring HATEOAS配置。 请注意,这将禁用上述ObjectMapper定制。

27.1.11 CORS 支持

跨原始资源共享(CORS)是大多数浏览器实现的W3C规范,允许您以灵活的方式指定什么样的跨域请求被授权,而不是使用一些不太安全和不太强大的方法,如IFRAME或JSONP。

从版本4.2起,Spring MVC支持CORS开箱即用。 在Spring Boot应用程序中的controller方法使用@CrossOrigin注解的CORS配置不需要任何特定的配置。 可以通过使用自定义的addCorsMappings(CorsRegistry)方法注册WebMvcConfigurer bean来定义全局CORS配置:

@Configuration
public class MyConfiguration {

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}

27.2 JAX-RS 和 Jersey

如果您喜欢JAX-RS编程模型的REST endpoints ,您可以使用一个可用的实现而不是Spring MVC。 如果您刚刚在应用程序上下文中注册了一个@Bean的Servlet或Filter,那么Jersey 1.x和Apache CXF的功能非常出色。 Jersey2.x有一些本地Spring支持,所以我们也提供自动配置支持它在Spring Boot与启动器。

要开始使用Jersey 2.x,只需将spring-boot-starter-jersey作为依赖项,然后您需要一个@Bean类型ResourceConfig,您可以在其中注册所有端点(endpoints):

@Component
public class JerseyConfig extends ResourceConfig {

public JerseyConfig() {
register(Endpoint.class);
}

}

Jersey对扫描可执行档案的包是相当有限的。 例如,当运行可执行的war文件时,它无法扫描在WEB-INF/classes中找到的包中的端点(endpoints)。 为了避免这种限制,不应使packages方法,并且应使用上述寄存器方法单独注册(register)端点。

您还可以注册任意数量的ResourceConfigCustomizer的实现bean,以实现更高级的自定义。

所有注册的端点都应为具有HTTP资源注解(@GET等)的@Components,例如。

@Component
@Path("/hello")
public class Endpoint {

@GET
public String message() {
return "Hello";
}

}

由于Endpoint是一个Spring @Component,所以Spring的生命周期由Spring管理,您可以使用@Autowired依赖关系并使用@Value注入外部配置。 默认情况下,Jersey servlet将被注册并映射到/ *。 您可以通过将@ApplicationPath添加到ResourceConfig来更改映射。

默认情况下,Jersey将通过@Bean以名为jerseyServletRegistration的ServletRegistrationBean类型在Servlet进行设置。 默认情况下,servlet将被初始化,但是您可以使用spring.jersey.servlet.load-on-startup进行自定义。您可以通过创建一个自己的同名文件来禁用或覆盖该bean。 您也可以通过设置spring.jersey.type = filter(在这种情况下,@Bean来替换或替换为jerseyFilterRegistration),使用Filter而不是Servlet。 servlet有一个@Order,您可以使用spring.jersey.filter.order设置。 可以使用spring.jersey.init.* 给出Servlet和过滤器注册的init参数,以指定属性的映射。

有一个Jersey示例,所以你可以看到如何设置。 还有一个Jersey1.x示例。 请注意,在Jersey1.x示例中,spring-boot maven插件已经被配置为打开一些Jersey jar,以便它们可以被JAX-RS实现扫描(因为示例要求它们在Filter注册中进行扫描) 。 如果您的任何JAX-RS资源作为嵌套的jar打包,您可能需要执行相同操作。

27.3 嵌入式servlet容器支持

Spring Boot包括对嵌入式Tomcat,Jetty和Undertow服务器的支持。 大多数开发人员将简单地使用适当的“Starter”来获取完全配置的实例。 默认情况下,嵌入式服务器将监听端口8080上的HTTP请求。

如果您选择在CentOS上使用Tomcat,请注意,默认情况下,临时目录用于存储已编译的JSP,文件上传等。当您的应用程序正在运行导致故障时,该目录可能会被tmpwatch删除。 为了避免这种情况,您可能需要自定义tmpwatch配置,以便tomcat.*目录不被删除,或配置server.tomcat.basedir,以便嵌入式Tomcat使用不同的位置

27.3.1 Servlets, Filters 和 listeners

当使用嵌入式servlet容器时,可以使用Spring bean或通过扫描Servlet组件(例如HttpSessionListener)注册Servlet规范中的Servlet,过滤器和所有监听器。

将Servlets,过滤器和监听器注册为Spring bean

任何Servlet,Filter或Servlet Listener 实例都会作为Spring bean注册到嵌入式容器中。 可以非常方便地在配置过程中引用您的application.properties中的值。

默认情况下,如果容器中只包含一个Servlet,它将映射到/。 在多个Servlet bean的情况下,bean名称将作为路径前缀。 过滤器(Filters)将映射到/*,默认过滤所有请求。

如果基于惯例的映射不够灵活,可以使用ServletRegistrationBean,FilterRegistrationBean和ServletListenerRegistrationBean类来完成控制。

27.3.2 Servlet Context 初始化

嵌入式servlet容器不会直接执行Servlet 3.0+ javax.servlet.ServletContainerInitializer接口或Spring的org.springframework.web.WebApplicationInitializer接口。 这样设计的目的旨在降低在war中运行的第三方库破坏Spring Boot应用程序的风险。

如果您需要在Spring Boot应用程序中执行servlet context 初始化,则应注册一个实现org.springframework.boot.context.embedded.ServletContextInitializer接口的bean。 单个onStartup方法提供对ServletContext的访问,并且如果需要,可以轻松地用作现有WebApplicationInitializer的适配器。

扫描Servlet,过滤器和监听器

使用嵌入式容器时,可以使用@ServletComponentScan启用@WebServlet,@WebFilter和@WebListener注解类的自动注册。

@ServletComponentScan在独立容器中不起作用,在该容器中将使用容器的内置发现机制。

27.3.3 EmbeddedWebApplicationContext

在Spring Boot引导下,将会使用一种新类型的ApplicationContext来支持嵌入式的servlet容器。 EmbeddedWebApplicationContext是一种特殊类型的WebApplicationContext,它通过搜索单个EmbeddedServletContainerFactory bean来引导自身。 通常,TomcatEmbeddedServletContainerFactory,JettyEmbeddedServletContainerFactory或UndertowEmbeddedServletContainerFactory将被自动配置。

您通常不需要知道这些实现类。 大多数应用程序将被自动配置,并将代表您创建适当的ApplicationContext和EmbeddedServletContainerFactory。

27.3.4 定制嵌入式servlet容器

可以使用Spring Environment属性配置常见的servlet容器设置。 通常您可以在application.properties文件中定义属性。

常用服务器设置包括:

  • 网络设置:侦听端口的HTTP请求(server.port),接口地址绑定到server.address等。
  • 会话设置:会话是否持久化(server.session.persistence),会话超时(server.session.timeout),会话数据的位置(server.session.store-dir)和session-cookie配置(server.session.cookie.*)。
  • 错误管理:错误页面的位置(server.error.path)等
  • SSL
  • HTTP压缩

Spring Boot尽可能地尝试公开常见设置,但并不总是可能的。 对于这些情况,专用命名空间提供服务器特定的定制(请参阅server.tomcat和server.undertow)。 例如,可以使用嵌入式servlet容器的特定功能来配置访问日志

有关完整列表,请参阅 ServerProperties 类。

用程序定制

如果需要以编程方式配置嵌入式servlet容器,您可以注册一个实现EmbeddedServletContainerCustomizer接口的Spring bean。 EmbeddedServletContainerCustomizer提供对ConfigurableEmbeddedServletContainer的访问,其中包含许多自定义设置方法。

import org.springframework.boot.context.embedded.*;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements EmbeddedServletContainerCustomizer {

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(9000);
}

}

直接自定义ConfigurableEmbeddedServletContainer

如果上述定制技术有太多限制,您可以自己注册TomcatEmbeddedServletContainerFactory,JettyEmbeddedServletContainerFactory或UndertowEmbeddedServletContainerFactory bean。

@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}

setter方法提供了许多配置选项。 如果您需要做更多的自定义,还会提供几种保护方法“钩子”。 有关详细信息,请参阅源代码文档。

27.3.5 JSP限制

当运行使用嵌入式servlet容器(并打包为可执行文档)的Spring Boot应用程序时,对JSP支持有一些限制。

  • 可以使用Tomcat和war包,即可执行的war将会起作用,并且也可以部署到标准容器(不限于但包括Tomcat)中。 由于Tomcat中的硬编码文件模式,可执行的jar将无法正常工作。
  • 可以使用Jetty和war包,即可执行的war将会起作用,并且也可以部署到任何标准的容器,它应该可以工作。
  • Undertow不支持JSP。
  • 创建自定义的error.jsp页面将不会覆盖默认视图以进行错误处理,而应使用自定义错误页面

28. Security

如果Spring Security位于类路径上,则默认情况下,Web应用程序将在所有HTTP端点上使用“basic”身份验证。 要向Web应用程序添加方法级安全性,您还可以使用所需的设置添加@EnableGlobalMethodSecurity。 有关更多信息,请参见“Spring Security Reference”。

默认的AuthenticationManager有一个用户(用户名’user’和随机密码,在应用程序启动时以INFO级别打印)

Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

如果您调整日志记录配置,请确保将org.springframework.boot.autoconfigure.security类别设置为记录INFO消息,否则将不会打印默认密码。

您可以通过提供security.user.password来更改密码。 这个和其他有用的属性通过 SecurityProperties(属性前缀“security”)进行外部化。

默认的安全配置在SecurityAutoConfiguration和从那里导入的类中实现(用于Web安全的SpringBootWebSecurityConfiguration和用于认证配置的AuthenticationManagerConfiguration,这在非Web应用程序中也是相关的)。 要完全关闭默认的Web应用程序安全配置,您可以使用@EnableWebSecurity添加一个bean(这不会禁用身份验证管理器配置或Actuator的安全性)。 要定制它,您通常使用WebSecurityConfigurerAdapter类型的外部属性和bean(例如添加基于表单的登录)。 要关闭身份验证管理器配置,您可以添加AuthenticationManager类型的bean,或者通过将AuthenticationManagerBuilder自动连接到您的一个@Configuration类中的方法来配置全局AuthenticationManager。 Spring Boot示例中有几个安全应用程序可以让您开始使用常见的用例

您在Web应用程序中获得的基本功能包括:

  • 具有内存存储和单个用户的AuthenticationManager Bean(请参阅用于用户属性的SecurityProperties.User)。
  • 对于常见的静态资源位置,忽略(不安全)路径(/css/**, /js/**, /images/**, /webjars/** and **/favicon.ico)。
  • HTTP所有其他端点的baseic security 。
  • 安全事件发布到Spring的ApplicationEventPublisher(成功、不成功的身份验证、拒绝访问)。
  • 默认情况下,Spring Security提供的常见的底层功能(HSTS,XSS,CSRF,缓存)都是打开的。

所有上述可以使用外部属性(security.*)打开、关闭或修改。 要覆盖访问规则而不更改任何其他自动配置的功能,请添加一个带有@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)的WebSecurityConfigurerAdapter类型的Bean,并配置它以满足您的需要。

默认情况下,WebSecurityConfigurerAdapter将匹配任何路径。 如果您不想完全覆盖Spring Boot自动配置的访问规则,您的适配器必须显式配置您要覆盖的路径。

28.1 OAuth2

如果您的类路径中有spring-security-oauth2,您可以利用一些自动配置来轻松设置授权或资源服务器。 有关完整的详细信息,请参阅“Spring Security OAuth 2开发人员指南”。

28.1.1 授权服务器

要创建授权服务器并授予访问令牌,您需要使用@EnableAuthorizationServer并提供security.oauth2.client.client-id和security.oauth2.client.client-secret]属性。 客户端将为您注册在内存中。

$ curl client:secret@localhost:8080/oauth/token -d grant_type=password -d username=user -d password=pwd

/token 端点的基本身份验证凭证是client-id和client-secret。 用户凭据是普通的Spring Security用户details (在Spring引导中默认为“user”和随机密码)。

要关闭自动配置并自行配置授权服务器功能,只需添加一个类型为AuthorizationServerConfigurer的@Bean。

28.1.2 资源服务器

要使用访问令牌(token),您需要一个资源服务器(可以与授权服务器相同)。 创建资源服务器很简单,只需添加@EnableResourceServer并提供一些配置,以允许服务器解码访问令牌。 如果您的应用程序也是授权服务器,则它已经知道如何解码令牌,无需做其他事情。 如果你的应用程序是一个独立的服务,那么你需要给它一些更多的配置,以下选项之一:

如果您同时指定user-info-uri和token-info-uri,那么您可以设置一个标志,表示优先于另一个(prefer-token-inf=true是默认值)。

或者(不是user-info-uri或token-info-uri的情况)如果令牌是JWT,您可以配置security.oauth2.resource.jwt.key-value来本地解码(key是验证密钥verification key)。 验证密钥值是对称秘密或PEM编码的RSA公钥。 如果您没有密钥,并且它是公开的,您可以提供一个可以使用security.oauth2.resource.jwt.key-uri下载的URI(具有“value”字段的JSON对象)。 例如在PWS上:

$ curl https://uaa.run.pivotal.io/token_key
{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"}

如果您使用security.oauth2.resource.jwt.key-uri,则应用程序启动时需要运行授权服务器。 如果找不到密钥,它将记录一个警告,并告诉您如何解决该问题。

如果您使用security.oauth2.resource.jwt.key-uri,则应用程序启动时需要运行授权服务器。 如果找不到密钥,它将会在日志记录一个警告,并告诉您如何解决该问题。

OAuth2资源由order security.oauth2.resource.filter-order的过滤器链保护,默认情况下保护执行器(actuator)端点的过滤器(所以执行器(actuator)端点将保留在HTTP Basic上,除非更改顺序)。

28.2 User Info中的令牌类型

Google和某些其他第三方身份认证提供商对在header中发送到用户信息端点的令牌类型名称更为严格。 默认值为“Bearer”,适合大多数提供程序并匹配规范,但如果需要更改,可以设置security.oauth2.resource.token-type。

28.3 自定义用户信息RestTemplate

如果您有user-info-uri,则资源服务器功能在内部使用OAuth2RestTemplate来获取用户身份验证信息。 这是以UserInfoRestTemplateFactory类型的@Bean提供的。 大多数提供程序的默认值应该是能满足正常使用,但有时您可能需要添加其他拦截器,或者更改请求验证器(例如:令牌如何附加到传出请求)。 进行自定义,只需创建一个类型为UserInfoRestTemplateCustomizer的bean - 它具有一个方法,在bean创建之后但在初始化之前将被调用。 这里定制的rest模板只能在内部进行验证。 或者,您可以定义自己的UserInfoRestTemplateFactory @Bean来完全控制。

要在YAML中设置RSA密钥值,请使用“pipe”继续标记将其分割成多行(“|”),并记住缩进键值(它是标准的 YAML 语言功能)。 例:

security:
oauth2:
resource:
jwt:
keyValue: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...
-----END PUBLIC KEY-----

28.3.1 Client

要使您的 web-app 进入OAuth2客户端,您可以简单地添加@ EnableOAuth2Client,Spring Boot将创建一个OAuth2ClientContext和OAuth2ProtectedResourceDetails,这些是创建OAuth2RestOperations所必需的。 Spring Boot不会自动创建这样的bean,但是您可以轻松创建自己的bean:

@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}

您可能需要添加限定符并查看您的配置,因为您的应用程序可能会定义多个RestTemplate。

此配置使用security.oauth2.client.*作为凭据(可能与授权服务器中使用的相同),但另外还需要知道授权服务器中的授权和令牌URI。 例如:

application.yml.

security:
oauth2:
client:
clientId: bd1c0a783ccdd1c9b9e4
clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
accessTokenUri: https://github.com/login/oauth/access_token
userAuthorizationUri: https://github.com/login/oauth/authorize
clientAuthenticationScheme: form

当您尝试使用OAuth2RestTemplate时,具有此配置的应用程序将重定向到Github进行授权。 如果您已经登录Github,您甚至不会注意到它已经被认证。 如果您的应用程序在端口8080上运行(在Github或其他提供商注册自己的客户端应用程序以获得更大的灵活性),这些特定的凭据才会起作用。

要限制客户端在获取访问令牌时要求的范围,您可以设置security.oauth2.client.scope(逗号分隔或YAML中的数组)。 默认情况下,scope是空的,由授权服务器决定其默认值,通常取决于客户端注册中的设置。

还有一个security.oauth2.client.client-authentication-scheme的设置,默认为“header”(但是如果像Github那样,您可能需要将其设置为“form”,例如,您的OAuth2提供程序不喜欢header 认证)。 事实上,security.oauth2.client.*属性绑定到AuthorizationCodeResourceDetails的一个实例,因此可以指定其所有的属性。

在非Web应用程序中,您仍然可以创建一个OAuth2RestOperations,它仍然连接到security.oauth2.client.*配置中。 在这种情况下,它是一个“客户端凭据令牌授予”,您如果使用它就请求它(并且不需要使用@EnableOAuth2Client或@EnableOAuth2Sso)。为了防止定义基础设施,只需从配置中删除security.oauth2.client.client-id(或使其成为空字符串)。

28.3.2 单点登录

OAuth2客户端可用于从提供商获取用户详细信息(如果此类功能可用),然后将其转换为Spring Security的身份验证令牌。 以上资源服务器通过user-info-uri属性支持此功能这是基于OAuth2的单点登录(SSO)协议的基础,Spring Boot可以通过提供@ EnableOAuth2Sso注解来轻松加入。 上面的Github客户端可以通过添加该注释并声明在何处查找端点(除了上面列出的security.oauth2.client.*配置)外,还可以保护所有资源并使用Github/user/endpoint进行身份验证:

application.yml.

security:
oauth2:
...
resource:
userInfoUri: https://api.github.com/user
preferTokenInfo: false

由于默认情况下所有路径都是安全的,所以没有可以向未经身份验证的用户显示“家”页面,并邀请他们登录(通过访问/登录路径或由security.oauth2.sso.login-path指定的路径) 。

由于默认情况下所有路径都是要求安全的,所以没有可以向未经身份验证的用户显示“home”页面,并邀请他们登录(通过访问/login 路径或由security.oauth2.sso.login-path指定的路径) 。

要自定义保护的访问规则或路径,因此您可以添加“home”页面,例如,@EnableOAuth2Sso可以添加到WebSecurityConfigurerAdapter,并且注解将使其被修饰和增强,以使所需的/login路径可以工作。 例如,这里我们简单地允许未经身份验证的访问“/“下的主页面,并保留其他所有内容的默认值:

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
public void init(WebSecurity web) {
web.ignore("/");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
}

}

28.4 Actuator Security

如果Actuator也在使用中,您会发现:

  • 即使应用程序端点不安全,管理端点也是安全的。
  • Security 事件将转换为AuditEvent实例,并发布到AuditEventRepository。
  • 默认用户将具有ACTUATOR角色以及USER角色。

Actuator的安全功能可以使用外部属性(management.security.*)进行修改。要覆盖应用程序访问规则,请添加一个类型为WebSecurityConfigurerAdapter的@Bean,如果您不想覆盖执行程序访问规则,则使用@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)或@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)覆盖执行器访问规则。

29. 使用SQL数据库

Spring Framework 为使用SQL数据库提供了广泛的支持。 从使用JdbcTemplate直接JDBC访问到完成“对象关系映射”技术,如Hibernate。Spring Data提供了额外的功能,直接从接口创建Repository实现,并使用约定从方法名称生成查询。

29.1 配置DataSource

Java的javax.sql.DataSource接口提供了使用数据库连接的标准方法。传统上,DataSource使用URL和一些凭据来建立数据库连接。

还可以查看更多高级示例的“操作方法”部分,通常可以完全控制DataSource的配置。

29.1.1 嵌入式数据库支持

使用内存中嵌入式数据库开发应用程序通常很方便。 显然,内存数据库不提供持久化存储; 您的应用程序启动时,您将需要初始化数据库,并在应用程序结束时丢弃数据。

“How-to”部分包含如何初始化数据库

Spring Boot可以自动配置嵌入式 H2HSQLDerby 数据库。 您不需要提供任何连接URL,只需将要使用的嵌入式数据库的依赖关系包含进去即可。

如果您在测试中使用此功能,您可能会注意到,整个测试套件都会重复使用相同的数据库,而不管您使用的应用程序上下文的数量。 如果要确保每个上下文都有一个单独的嵌入式数据库,您应该将spring.datasource.generate-unique-name设置为true。

例如,典型的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控制数据库何时关闭,从而确保在不再需要访问数据库时发生这种情况。

29.1.2 连接到生产环境数据库

生产数据库连接也可以使用连接池数据源自动配置。 这是选择具体实现的算法:

  • 我们更喜欢Tomcat连接池DataSource的性能和并发性,所以如果可用,我们总是选择它。
  • 否则,如果HikariCP可用,我们将使用它。
  • 如果Tomcat池数据源和HikariCP都不可用,并且如果Commons DBCP可用,我们将使用它,但是我们不建议在生产中使用它,并且不支持它。
  • 最后,如果Commons DBCP2可用,我们将使用它。

如果您使用spring-boot-starter-jdbc或spring-boot-starter-data-jpa 的startters,您将自动获得对tomcat-jdbc的依赖。

您可以完全绕过该算法,并通过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将尝试自动配置嵌入式数据库。

您通常不需要指定驱动程序类名称,因为Spring Boot可以从url为大多数数据库推断出驱动程序名称。

对于要创建的池数据源,我们需要能够验证有效的Driver类是否可用,所以我们在做任何事情之前检查它。 即 如果您设置spring.datasource.driver-class-name=com.mysql.jdbc.Driver,那么该类必须可加载。

有关更多支持的选项,请参阅 DataSourceProperties。 这些是标准选项,无论实际执行情况如何。 还可以使用各自的前缀(spring.datasource.tomcat.*,spring.datasource.hikari.*和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

29.1.3 连接到JNDI DataSource

如果要将Spring Boot应用程序部署到应用程序服务器,则可能需要使用应用程序服务器内置功能来配置和管理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

29.2 使用JdbcTemplate

Spring的JdbcTemplate和NamedParameterJdbcTemplate类是自动配置的,您可以将它们直接连接到您自己的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;
}

// ...

}

29.3 JPA 和 ‘Spring Data’

Java Persistence API是一种标准技术,可让您将对象映射到关系数据库。 spring-boot-starter-data-jpa POM提供了一种快速入门的方法。 它提供以下关键依赖:

  • Hibernate - 最受欢迎的JPA实现之一。
  • Spring Data JPA - 可以轻松实现基于JPA的存储库。
  • Spring ORMs - 来自Spring Framework的核心ORM支持。

我们不会在这里介绍太多的JPA或Spring Data的细节。 您可以从spring.io中查看“使用JPA访问数据”指南,并阅读Spring Data JPAHibernate参考文档。

默认情况下,Spring Boot使用Hibernate 5.0.x. 但是,如果您愿意,也可以使用4.3.x或5.2.x。 请参考 Hibernate 4Hibernate 5.2 示例,看看如何做到这一点。

29.3.1 实体类

传统上,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.country = country;
}

public String getName() {
return this.name;
}

public String getState() {
return this.state;
}

// ... etc

}

您可以使用@EntityScan注解自定义实体扫描位置。 请参见第77.4节“从Spring配置中分离@Entity定义”操作方法。

29.3.2 Spring Data JPA Repositories

Spring Data JPA库是可以定义用于访问数据的接口。 JPA查询是从您的方法名称自动创建的。 例如,CityRepository接口可以声明findAllByState(String state)方法来查找给定状态下的所有城市。

对于更复杂的查询,您可以使用Spring数据查询注解来注解您的方法。

Spring数据存储库通常从Repository或CrudRepository接口扩展。 如果您正在使用自动配置,将从包含主配置类(通过@EnableAutoConfiguration或@SpringBootApplication注解的包)的包中搜索存储库(repositories)。

这是一个典型的Spring数据库:

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 findByNameAndCountryAllIgnoringCase(String name, String country);

}

我们只是触及了Spring Data JPA的表面。 有关完整的详细信息,请查阅其参考文档

29.3.3 创建和删除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属性一起设置。 例:

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

hibernate.globally_quoted_identifiers 传递给Hibernate实体管理器。

默认情况下,DDL执行(或验证)将延迟到ApplicationContext启动。 还有一个spring.jpa.generate-ddl标志,但是如果Hibernate 自动配置是激活的,那么它将不会被使用,因为ddl-auto配置更好。

29.3.4 在View中打开EntityManager

如果您正在运行Web应用程序,Spring Boot将默认注册OpenEntityManagerInViewInterceptor来应用“查看”中的“打开EntityManager”模式,即允许在Web视图中进行延迟加载。 如果你不想要这个行为,你应该在你的application.properties中将spring.jpa.open-in-view设置为false。

29.4 使用H2的Web控制台

H2数据库提供了一个基于浏览器的控制台,Spring Boot可以为您自动配置。 满足以下条件时,控制台将自动配置:

如果您不使用Spring Boot的开发人员工具,但仍希望使用H2的控制台,那么可以通过配置一个值为true的spring.h2.console.enabled属性来实现。 H2控制台仅用于开发期间,因此应注意确保spring.h2.console.enabled在生产中未设置为true。

29.4.1 更改H2控制台的路径

默认情况下,控制台路径将在 /h2-console上。 您可以使用spring.h2.console.path属性来自定义控制台的路径。

29.4.2 保护H2控制台

当Spring Security位于类路径上且启用了基本身份验证时,H2控制台将自动使用基本身份验证进行保护。 以下属性可用于自定义安全配置:

  • security.user.role
  • security.basic.authorize-mode
  • security.basic.enabled

29.5 使用jOOQ

Java面向对象查询(jOOQ)是Data Geekery的产品,它从数据库生成Java代码,并通过流畅的API构建类型安全的SQL查询。 商业版和开源版都可以与Spring Boot一起使用。

29.5.1 代码生成

为了使用jOOQ类型安全的查询,您需要从数据库模式生成Java类。 您可以按照jOOQ用户手册中的说明进行操作。 如果您正在使用jooq-codegen-maven插件(并且还使用spring-boot-starter-parent“父POM”),您可以安全地省略插件的标签。 您还可以使用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>

29.5.2 使用 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);
}

29.5.3 定制jOOQ

您可以通过在application.properties中设置spring.jooq.sql-dialect来自定义jOOQ使用的SQL方言。 例如,要指定Postgres,您可以添加:

spring.jooq.sql-dialect=Postgres

通过定义自己的@Bean定义可以实现更高级的定制,这些定义将在创建jOOQ配置时使用。您可以为以下jOOQ类型定义bean:

  • ConnectionProvider
  • TransactionProvider
  • RecordMapperProvider
  • RecordListenerProvider
  • ExecuteListenerProvider
  • VisitListenerProvider

如果要完全控制jOOQ配置,您还可以创建自己的org.jooq.Configuration @Bean。

30. 使用NoSQL技术

Spring Data提供了额外的项目,可帮助您访问各种NoSQL技术,包括MongoDBNeo4JElasticsearchSolrRedisGemfireCassandraCouchbaseLDAP。 Spring Boot为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase和LDAP提供了自动配置; 您也可以使用其他项目,但您需要自行配置它们。 请参阅projects.spring.io/spring-data中相应的参考文档。

30.1 Redis

Redis是一个缓存,消息代理并有功能丰富的键值存储数据库。Spring Boot提供了Jedis客户端库的基本自动配置和Spring Data Redis提供的抽象。 有一个spring-boot-starter-data-redis“Starter”用于以方便的方式收集依赖关系。

30.1.1 连接到Redis

您可以像任何其他Spring Bean一样注入自动配置的RedisConnectionFactory,StringRedisTemplate或vanilla RedisTemplate实例。 默认情况下,实例将尝试使用localhost:6379连接到Redis服务器:

@Component
public class MyBean {

private StringRedisTemplate template;

@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}

// ...

}

如果您添加了您自己的任何自动配置类型的@Bean,它将替换默认值(除了在RedisTemplate的情况下,排除是基于bean名称“redisTemplate”而不是其类型)。 如果commons-pool2在类路径上,则默认情况下将获得一个pooled连接工厂。

30.2 MongoDB

MongoDB是一个开源的NoSQL文档数据库,它使用类似JSON的架构,而不是传统的基于表的关系数据。 Spring Boot为MongoDB提供了几种便利,包括spring-boot-starter-data-mongodb’Starter’。