本节提供了一些在使用Spring Boot时经常出现的常见`我该怎么做...''问题的答案。它的覆盖范围不是很详尽,但是确实覆盖了很多。<br />如果您有一个我们不在此讨论的特定问题,则可能需要查看[stackoverflow.com](https://stackoverflow.com/tags/spring-boot)来查看是否有人已经提供了答案。这也是一个提出新问题的好地方(请使用spring-boot`标签)。
我们也很乐意扩展此部分。如果您想添加“操作方法”,请向我们发送请求请求

1. Spring Boot应用程序

本部分包括与Spring Boot应用程序直接相关的主题。

1.1。创建自己的FailureAnalyzer

FailureAnalyzer是在启动时拦截异常并将其转换为人类可读消息的好方法,并包装在内FailureAnalysis。Spring Boot为与应用程序上下文相关的异常,JSR-303验证等提供了这种分析器。您也可以创建自己的。
AbstractFailureAnalyzer是一个方便的扩展,FailureAnalyzer它检查要处理的异常中是否存在指定的异常类型。您可以对此进行扩展,以便您的实现只有在实际出现异常时才有机会处理该异常。如果由于某种原因无法处理该异常,请返回null以使另一个实现有机会处理该异常。
FailureAnalyzer实施必须在中注册META-INF/spring.factories。以下示例注册ProjectConstraintViolationFailureAnalyzer

  1. org.springframework.boot.diagnostics.FailureAnalyzer=\
  2. com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要访问BeanFactoryEnvironment,则FailureAnalyzer可以分别实现BeanFactoryAwareEnvironmentAware

1.2。自动配置故障排除

Spring Boot自动配置会尽力“做正确的事”,但是有时事情会失败,并且很难说出原因。
ConditionEvaluationReport任何Spring Boot中都有一个非常有用的功能ApplicationContext。如果启用DEBUG日志记录输出,则可以看到它。如果使用spring-boot-actuator(请参阅“执行器”一章),则还有一个conditions终结点,该终结点以JSON形式呈现报告。使用该端点调试应用程序,并在运行时查看Spring Boot已添加(未添加)的功能。
通过查看源代码和Javadoc,可以回答更多问题。阅读代码时,请记住以下经验法则:

  • 查找称为的类*AutoConfiguration并阅读其源代码。特别注意@Conditional*注释,以了解它们启用了哪些功能以及何时启用。添加--debug到命令行或“系统”属性-Ddebug以在控制台上获取应用程序中做出的所有自动配置决策的日志。在启用了执行器的运行应用程序中,查看conditions端点(/actuator/conditions或等效的JMX)以获取相同信息。
  • 查找属于@ConfigurationProperties(例如ServerProperties)的类,然后从中读取可用的外部配置选项。该@ConfigurationProperties注释具有一个name充当前缀外部性能属性。因此,ServerProperties拥有prefix="server"和它的配置性能server.portserver.address以及其他。在启用了执行器的运行应用程序中,查看configprops端点。
  • 寻找对bind方法的使用,以一种轻松的方式Binder将配置值明确地拉出Environment。它通常与前缀一起使用。
  • 查找@Value直接绑定到的注释Environment
  • 寻找@ConditionalOnExpression注释以响应SpEL表达式来打开或关闭功能,这些注释通常使用从中解析的占位符进行评估Environment

    1.3。启动之前自定义环境或ApplicationContext

    一个SpringApplication具有ApplicationListenersApplicationContextInitializers被用于应用自定义的背景或环境。Spring Boot加载了许多此类自定义项,以供内部使用META-INF/spring.factories。注册其他自定义项的方法有多种:

  • 在运行之前,通过对每个应用程序进行编程,方法是调用addListenersaddInitializers方法SpringApplication

  • 通过设置context.initializer.classescontext.listener.classes属性,以声明方式针对每个应用程序。
  • 声明性地,对于所有应用程序,通过添加META-INF/spring.factories和打包一个jar文件,这些文件都被应用程序用作库。

SpringApplication发送一些特殊ApplicationEvents的听众(背景下创造了一些甚至更早),然后注册了在公布的事件监听器ApplicationContext为好。有关完整列表,请参见“ Spring Boot功能”部分中的“应用程序事件和侦听器”。
还可以使用来自定义Environment刷新应用程序上下文之前的EnvironmentPostProcessor。每个实现都应在中注册META-INF/spring.factories,如以下示例所示:
org.springframework.boot.env.EnvironmentPostProcessor = com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将其添加到中Environment。例如,以下示例从类路径加载YAML配置文件:

  1. public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {
  2. private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
  3. @Override
  4. public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
  5. Resource path = new ClassPathResource("com/example/myapp/config.yml");
  6. PropertySource<?> propertySource = loadYaml(path);
  7. environment.getPropertySources().addLast(propertySource);
  8. }
  9. private PropertySource<?> loadYaml(Resource path) {
  10. if (!path.exists()) {
  11. throw new IllegalArgumentException("Resource " + path + " does not exist");
  12. }
  13. try {
  14. return this.loader.load("custom-resource", path).get(0);
  15. }
  16. catch (IOException ex) {
  17. throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
  18. }
  19. }
  20. }
Environment已经准备与所有常见的财产来源春天引导加载默认。因此可以从环境中获取文件的位置。前面的示例将custom-resource属性源添加到列表的末尾,以便在其他任何常见位置定义的键具有优先权。定制实现可以定义另一个顺序。
在使用@PropertySource你的@SpringBootApplication似乎是加载在一个自定义资源的便利方式Environment,我们不建议这样做。Environment在刷新应用程序上下文之前,不会将此类属性源添加到中。现在配置某些属性(如logging.*spring.main.*在刷新开始之前先读取)为时已晚。

1.4。建立ApplicationContext层次结构(添加父上下文或根上下文)

您可以使用ApplicationBuilder该类创建父/子ApplicationContext层次结构。有关更多信息,请参见“ Spring Boot功能”部分中的“ spring-boot-features.html ”。

1.5。创建一个非Web应用程序

并非所有的Spring应用程序都必须是Web应用程序(或Web服务)。如果要在main方法中执行一些代码,又要引导Spring应用程序以设置要使用的基础结构,则可以使用SpringApplicationSpring Boot的功能。A根据是否认为需要Web应用程序来SpringApplication更改其ApplicationContext类。您可以做的第一件事是让服务器相关的依赖项(例如Servlet API)脱离类路径。如果你不能做到这一点(例如,您从相同的代码库的两个应用程序),那么你可以显式调用setWebApplicationType(WebApplicationType.NONE)您的SpringApplication实例或设置applicationContextClass属性(通过Java API或与外部属性)。您可以将要作为业务逻辑运行的应用程序代码实现为CommandLineRunner并作为@Bean定义放到上下文中。

2.属性和配置

本节包括有关设置和读取属性和配置设置以及它们与Spring Boot应用程序的交互的主题。

2.1。在构建时自动扩展属性

除了可以对项目的构建配置中也指定的某些属性进行硬编码之外,您可以通过使用现有构建配置自动扩展它们。在Maven和Gradle中都是可能的。

2.1.1。使用Maven自动扩展属性

您可以使用资源过滤从Maven项目自动扩展属性。如果使用spring-boot-starter-parent,则可以使用@..@占位符引用Maven的“项目属性” ,如以下示例所示:
特性
Yaml

  1. app:
  2. encoding: "@project.build.sourceEncoding@"
  3. java:
  4. version: "@java.version@"
这样只会过滤生产配置(也就是说,不会对进行过滤src/test/resources)。
如果启用该addResources标志,则spring-boot:run目标可以src/main/resources直接添加到类路径中(用于热重载)。这样做避免了资源过滤和此功能。相反,您可以使用exec:java目标或自定义插件的配置。有关更多详细信息,请参见插件使用情况页面

如果您不使用入门级父级,则需要在<build/>元素中包括以下元素pom.xml

  1. <resources>
  2. <resource>
  3. <directory>src/main/resources</directory>
  4. <filtering>true</filtering>
  5. </resource>
  6. </resources>

您还需要在其中包含以下元素<plugins/>

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-resources-plugin</artifactId>
  4. <version>2.7</version>
  5. <configuration>
  6. <delimiters>
  7. <delimiter>@</delimiter>
  8. </delimiters>
  9. <useDefaultDelimiters>false</useDefaultDelimiters>
  10. </configuration>
  11. </plugin>
useDefaultDelimiters如果${placeholder}在配置中使用标准的Spring占位符(例如),则 该属性很重要。如果该属性未设置为false,则可以通过构建扩展这些属性。

2.1.2。使用Gradle自动扩展属性

您可以通过配置Java插件的processResources任务来自动扩展Gradle项目中的属性,如以下示例所示:

  1. processResources {
  2. expand(project.properties)
  3. }

然后,您可以使用占位符来引用Gradle项目的属性,如以下示例所示:
特性
Yaml

  1. app:
  2. name: "${name}"
  3. description: "${description}"
Gradle的expand方法使用Groovy的方法SimpleTemplateEngine来转换${..}令牌。该${..}风格的冲突与Spring自己的财产占位符机制。要将Spring属性占位符与自动扩展一起使用,请按以下步骤转义Spring属性占位符:\${..}

2.2。外部化SpringApplication的配置

ASpringApplication具有bean属性(主要是setter),因此在创建应用程序时可以使用其Java API修改其行为。或者,您可以通过在中设置属性来外部化配置spring.main.*。例如,在中application.properties,您可能具有以下设置:
特性
Yaml

  1. spring:
  2. main:
  3. web-application-type: "none"
  4. banner-mode: "off"

然后,Spring Boot标语不会在启动时打印,并且应用程序也不会启动嵌入式Web服务器。
外部配置中定义的属性会覆盖用Java API指定的值,但用于创建的源的显着例外除外ApplicationContext。考虑以下应用程序:

  1. new SpringApplicationBuilder()
  2. .bannerMode(Banner.Mode.OFF)
  3. .sources(demo.MyApp.class)
  4. .run(args);

现在考虑以下配置:
特性
Yaml

  1. spring:
  2. main:
  3. sources: "com.acme.Config,com.acme.ExtraConfig"
  4. banner-mode: "console"

实际应用中,现在示出的旗帜(如通过配置覆盖),并使用了三个源ApplicationContext(按以下顺序): ,demo.MyAppcom.acme.Configcom.acme.ExtraConfig

2.3。更改应用程序外部属性的位置

默认情况下,来自不同来源的属性Environment将以定义的顺序添加到Spring中(有关确切顺序,请参见“ Spring Boot功能”部分中的“ spring-boot-features.html ”)。
您还可以提供以下系统属性(或环境变量)来更改行为:

  • spring.config.nameSPRING_CONFIG_NAME):默认为application作为文件名的根。
  • spring.config.locationSPRING_CONFIG_LOCATION):要加载的文件(例如类路径资源或URL)。Environment为此文档设置了单独的属性源,可以通过系统属性,环境变量或命令行来覆盖它。

无论您在环境中进行什么设置,Spring Boot都将始终application.properties如上所述进行加载。默认情况下,如果使用YAML,则扩展名为’.yml’的文件也将添加到列表中。
Spring Boot记录了在该DEBUG级别加载的配置文件以及在该级别找不到的候选文件TRACE
请参阅参考资料ConfigFileApplicationListener

2.4。使用“简短”命令行参数

有些人喜欢使用(例如)--port=9000而不是--server.port=9000在命令行上设置配置属性。您可以通过在中使用占位符来启用此行为application.properties,如以下示例所示:
特性
Yaml

  1. server:
  2. port: "${port:8080}"
如果您从spring-boot-starter-parentPOM继承,则将的默认过滤器令牌maven-resources-plugins从更改${*}@(即,@maven.token@而不是${maven.token}),以防止与Spring样式的占位符冲突。如果您application.properties直接启用了Maven过滤,则可能还需要更改默认过滤器令牌以使用其他定界符
在这种特定情况下,端口绑定可在PaaS环境(例如Heroku或Cloud Foundry)中工作。在这两个平台中,PORT环境变量是自动设置的,并且Spring可以绑定到Environment属性的大写同义词。

2.5。对外部属性使用YAML

YAML是JSON的超集,因此是一种方便的语法,用于以分层格式存储外部属性,如以下示例所示:

  1. spring:
  2. application:
  3. name: "cruncher"
  4. datasource:
  5. driver-class-name: "com.mysql.jdbc.Driver"
  6. url: "jdbc:mysql://localhost/test"
  7. server:
  8. port: 9000

创建一个名为的文件application.yml,并将其放在类路径的根目录中。然后添加snakeyaml到您的依赖项(Maven坐标org.yaml:snakeyaml,如果使用,则已经包含在内spring-boot-starter)。将YAML文件解析为Java Map<String,Object>(如JSON对象),然后Spring Boot展宽地图,使其深一层,并具有句点分隔的键,这是许多人习惯使用PropertiesJava中的文件的原因。
前面的示例YAML对应于以下application.properties文件:

  1. spring.application.name=cruncher
  2. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  3. spring.datasource.url=jdbc:mysql://localhost/test
  4. server.port=9000

有关YAML的更多信息,请参见“ Spring Boot功能”部分中的“ spring-boot-features.html ”。

2.6。设置活动弹簧轮廓

SpringEnvironment为此提供了一个API,但是您通常会设置一个System属性(spring.profiles.active)或OS环境变量(SPRING_PROFILES_ACTIVE)。另外,您可以使用-D参数启动应用程序(请记住将其放在主类或jar存档之前),如下所示:
$ java -jar -Dspring.profiles.active =生产演示-0.0.1-SNAPSHOT.jar
在Spring Boot中,您还可以在中设置活动配置文件application.properties,如以下示例所示:
特性
Yaml

  1. spring:
  2. profiles:
  3. active: "production"

以这种方式设置的值将由“系统”属性或环境变量设置代替,而不由SpringApplicationBuilder.profiles()方法替代。因此,后一种Java API可用于扩充配置文件,而无需更改默认值。
有关更多信息,请参见“ Spring Boot功能”部分中的“ spring-boot-features.html ”。

2.7。根据环境更改配置

Spring Boot支持多文档的YAML和属性文件(有关详细信息,请参见spring-boot-features.html),可以根据活动的配置文件有条件地对其进行激活。
如果文档包含spring.config.activate.on-profile键,则将配置文件值(以逗号分隔的配置文件列表或配置文件表达式)馈入SpringEnvironment.acceptsProfiles()方法。如果配置文件表达式匹配,则该文档将包含在最终合并中(否则,则不包括),如以下示例所示:
特性
Yaml

  1. server:
  2. port: 9000
  3. ---
  4. spring:
  5. config:
  6. activate:
  7. on-profile: "development"
  8. server:
  9. port: 9001
  10. ---
  11. spring:
  12. config:
  13. activate:
  14. on-profile: "production"
  15. server:
  16. port: 0

在前面的示例中,默认端口为9000。但是,如果名为“ development”的Spring概要文件处于活动状态,则该端口为9001。如果“ production”为活动,则该端口为0。

这些文档按照它们遇到的顺序合并。以后的值将覆盖以前的值。

2.8。发现外部属性的内置选项

Spring Boot在运行时将来自application.properties(或.yml文件和其他位置)的外部属性绑定到应用程序中。在一个位置上没有(而且从技术上来说不是)所有受支持属性的详尽列表,因为贡献可能来自类路径上的其他jar文件。
具有Actuator功能的正在运行的应用程序具有一个configprops终结点,该终结点显示可通过访问的所有绑定和可绑定属性@ConfigurationProperties
附录中包含一个application.properties示例,其中列出了Spring Boot支持的最常见属性。最终列表来自搜索源代码中的@ConfigurationProperties@Value注释,以及偶尔使用Binder。有关加载属性的确切顺序的更多信息,请参见“ spring-boot-features.html ”。

3.嵌入式Web服务器

每个Spring Boot Web应用程序都包含一个嵌入式Web服务器。此功能导致许多方法问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节回答这些问题。

3.1。使用其他Web服务器

许多Spring Boot启动器都包含默认的嵌入式容器。

  • 对于servlet堆栈应用程序,通过spring-boot-starter-web包括来包括Tomcat spring-boot-starter-tomcat,但是您可以使用spring-boot-starter-jettyspring-boot-starter-undertow代替。
  • 对于反应栈的应用,spring-boot-starter-webflux包括反应堆的Netty通过包括spring-boot-starter-reactor-netty,但你可以使用spring-boot-starter-tomcatspring-boot-starter-jettyspring-boot-starter-undertow代替。

切换到其他HTTP服务器时,您需要将默认依赖项交换为所需的依赖项。为了帮助完成此过程,Spring Boot为每个受支持的HTTP服务器提供了一个单独的启动器。
以下Maven示例显示了如何排除Tomcat并包括Spring MVC的Jetty:

  1. <properties>
  2. <servlet-api.version>3.1.0</servlet-api.version>
  3. </properties>
  4. <dependency>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-starter-web</artifactId>
  7. <exclusions>
  8. <!-- Exclude the Tomcat dependency -->
  9. <exclusion>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-tomcat</artifactId>
  12. </exclusion>
  13. </exclusions>
  14. </dependency>
  15. <!-- Use Jetty instead -->
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-jetty</artifactId>
  19. </dependency>
Servlet API的版本已被覆盖,因为与Tomcat 9和Undertow 2.0不同,Jetty 9.4不支持Servlet 4.0。

以下Gradle示例显示了如何使用Undertow代替Spring WebFlux的Reactor Netty:

  1. configurations.all {
  2. resolutionStrategy.dependencySubstitution.all { dependency ->
  3. if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.module == 'spring-boot-starter-reactor-netty') {
  4. dependency.useTarget("org.springframework.boot:spring-boot-starter-undertow:$dependency.requested.version", 'Use Undertow instead of Reactor Netty')
  5. }
  6. }
  7. }
  8. dependencies {
  9. compile 'org.springframework.boot:spring-boot-starter-webflux'
  10. // ...
  11. }
spring-boot-starter-reactor-netty使用WebClient该类是必需的,因此即使您需要包括其他HTTP服务器,也可能需要保持对Netty的依赖。

3.2。禁用Web服务器

如果您的类路径包含启动Web服务器所需的位,则Spring Boot将自动启动它。要禁用此行为,请WebApplicationType在中配置application.properties,如以下示例所示:
特性
Yaml

  1. spring:
  2. main:
  3. web-application-type: "none"

3.3。更改HTTP端口

在独立应用程序中,主HTTP端口默认为,8080但可以使用server.port(例如,在application.propertiesSystem属性中或作为System属性)进行设置。由于轻松地绑定了Environment值,因此您还可以使用SERVER_PORT(例如,作为OS环境变量)。
要完全关闭HTTP端点但仍创建一个WebApplicationContext,请使用server.port=-1(这样做有时对测试很有用)。
有关更多详细信息,请参阅“ Spring Boot功能”部分中的“ spring-boot-features.html ”或ServerProperties源代码。

3.4。使用随机未分配的HTTP端口

要扫描可用端口(使用OS本机来防止冲突),请使用server.port=0

3.5。在运行时发现HTTP端口

您可以从日志输出或WebServerApplicationContext通过其端口访问服务器运行的端口WebServer。最好的方法是确保它已被初始化,是添加一个@BeantypeApplicationListener<WebServerInitializedEvent>并在事件发布时将其从事件中拉出。
使用的测试@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)还可以通过使用@LocalServerPort批注将实际端口注入字段中,如以下示例所示:

  1. @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
  2. public class MyWebIntegrationTests {
  3. @LocalServerPort
  4. int port;
  5. // ...
  6. }
@LocalServerPort是的元注释@Value("${local.server.port}")。不要尝试在常规应用程序中注入端口。如我们所见,仅在初始化容器之后才设置该值。与测试相反,应早处理应用程序代码回调(在值实际可用之前)。

3.6。启用HTTP响应压缩

Jetty,Tomcat和Undertow支持HTTP响应压缩。可以在中启用它application.properties,如下所示:
特性
Yaml

  1. server:
  2. compression:
  3. enabled: true

默认情况下,响应的长度必须至少为2048个字节才能执行压缩。您可以通过设置server.compression.min-response-size属性来配置此行为。
默认情况下,仅当响应的内容类型为以下之一时,它们才被压缩:

  • text/html
  • text/xml
  • text/plain
  • text/css
  • text/javascript
  • application/javascript
  • application/json
  • application/xml

您可以通过设置server.compression.mime-types属性来配置此行为。

3.7。配置SSL

可以通过设置各种server.ssl.*属性来声明性地配置SSL ,通常在application.properties或中application.yml。以下示例显示了在中设置SSL属性application.properties
特性
Yaml

  1. server:
  2. port: 8443
  3. ssl:
  4. key-store: "classpath:keystore.jks"
  5. key-store-password: "secret"
  6. key-password: "another-secret"

有关Ssl所有受支持属性的详细信息,请参见。
使用上述示例的配置意味着应用程序不再在端口8080上支持纯HTTP连接器。SpringBoot不支持通过进行HTTP连接器和HTTPS连接器的配置application.properties。如果要同时拥有两者,则需要以编程方式配置其中之一。我们建议您使用application.propertiesHTTPS进行配置,因为HTTP连接器是两者中以编程方式配置的比较容易的方法。

3.8。配置HTTP / 2

您可以使用server.http2.enabled配置属性在Spring Boot应用程序中启用HTTP / 2支持。该支持取决于所选的Web服务器和应用程序环境,因为并非所有JDK8版本都立即支持该协议。

Spring Boot不建议使用h2cHTTP / 2协议的明文版本。因此,以下各节要求您首先配置SSL。如果仍然选择使用h2c,则可以查看专用部分

3.8.1。Tomcat的HTTP / 2

默认情况下,Spring Boot随Tomcat 9.0.x一起提供,当使用JDK 9或更高版本时,Tomcat 9.0.x支持HTTP / 2。另外,如果libtcnative库及其依赖项已安装在主机操作系统上,则可以在JDK 8上使用HTTP / 2 。
如果没有,则必须使库目录可用于JVM库路径。您可以使用JVM参数(例如)来执行此操作-Djava.library.path=/usr/local/opt/tomcat-native/lib。有关更多信息,请参见Tomcat官方文档
在没有该本机支持的情况下在JDK 8上启动Tomcat 9.0.x会记录以下错误:
错误8787-[[main] oacoyote.http11.Http11NioProtocol:[h2]的升级处理程序[org.apache.coyote.http2.Http2Protocol]仅支持通过ALPN进行升级,但已为[“ https-jsse-nio”配置-8443“]连接器不支持ALPN。
此错误不是致命错误,并且该应用程序仍以HTTP / 1.1 SSL支持开头。

3.8.2。HTTP / 2与码头

对于HTTP / 2支持,Jetty需要附加的org.eclipse.jetty.http2:http2-server依赖关系。现在,根据您的部署,还需要选择其他依赖项:

  • org.eclipse.jetty:jetty-alpn-java-server 适用于在JDK9 +上运行的应用程序
  • org.eclipse.jetty:jetty-alpn-openjdk8-server 适用于在JDK8u252 +上运行的应用程序
  • org.eclipse.jetty:jetty-alpn-conscrypt-server和没有JDK要求的Conscrypt库

    3.8.3。HTTP / 2和Reactor Netty

    spring-boot-webflux-starter默认情况下,反应堆的Netty作为服务器使用。使用JDK 9或更高版本的JDK支持,可以将Reactor Netty配置为HTTP / 2。对于JDK 8环境,或为了获得最佳的运行时性能,此服务器还支持带有本机库的HTTP / 2。为此,您的应用程序需要具有其他依赖关系。
    Spring Boot管理io.netty:netty-tcnative-boringssl-static“超级罐”的版本,其中包含所有平台的本机库。开发人员可以选择使用分类器仅导入所需的依赖项(请参阅Netty官方文档)。

    3.8.4。带有Undertow的HTTP / 2

    从Undertow 1.4.0+开始,在JDK8上没有任何其他要求就支持HTTP / 2。

    3.8.5。支持服务器的HTTP / 2明文

    要启用具有明文支持的HTTP / 2,您需要将该server.http2.enabled属性设置为false,而是应用特定于您选择的服务器的定制程序:
    对于Tomcat,我们需要添加一个升级协议:
    1. @Bean
    2. public TomcatConnectorCustomizer connectorCustomizer() {
    3. return (connector) -> connector.addUpgradeProtocol(new Http2Protocol());
    4. }
    对于Jetty,我们需要向现有连接器添加连接工厂:
    1. @Bean
    2. public JettyServerCustomizer serverCustomizer() {
    3. return (server) -> {
    4. HttpConfiguration configuration = new HttpConfiguration();
    5. configuration.setSendServerVersion(false);
    6. Arrays.stream(server.getConnectors())
    7. .filter(connector -> connector instanceof ServerConnector)
    8. .map(ServerConnector.class::cast)
    9. .forEach(connector -> {
    10. connector.addConnectionFactory(new HTTP2CServerConnectionFactory(configuration));
    11. });
    12. };
    13. }
    对于Netty,我们需要添加h2c作为受支持的协议:
    1. @Bean
    2. public NettyServerCustomizer serverCustomizer() {
    3. return (server) -> server.protocol(HttpProtocol.H2C);
    4. }
    对于Undertow,我们需要启用HTTP2选项:
    1. @Bean
    2. public UndertowBuilderCustomizer builderCustomizer() {
    3. return (builder) -> {
    4. builder.setServerOption(ENABLE_HTTP2, true);
    5. };
    6. }

    3.9。配置Web服务器

    通常,您应该首先考虑使用许多可用的配置键之一,并通过在您的application.properties(或application.yml,或环境等)中添加新条目来自定义Web服务器。请参阅“发现外部属性的内置选项”。该server.*命名空间是非常有用的在这里,它包括命名空间一样server.tomcat.*server.jetty.*和其他人,对服务器的特定功能。请参阅appendix-application-properties.html的列表。
    前面的部分已经介绍了许多常见的用例,例如压缩,SSL或HTTP / 2。但是,如果您的用例不存在配置密钥,则应查看WebServerFactoryCustomizer。您可以声明一个这样的组件并访问与您选择的服务器相关的工厂:您应该为所选服务器(Tomcat,Jetty,Reactor Netty,Undertow)和所选Web堆栈(Servlet或Reactive)选择变体。
    以下示例适用于具有spring-boot-starter-web(Servlet堆栈)的Tomcat :
    1. @Component
    2. public class MyTomcatWebServerCustomizer
    3. implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    4. @Override
    5. public void customize(TomcatServletWebServerFactory factory) {
    6. // customize the factory here
    7. }
    8. }
    | | Spring Boot在内部使用该基础架构来自动配置服务器。自动配置的WebServerFactoryCustomizerBean的顺序为,0并且将在任何用户定义的定制程序之前进行处理,除非它具有明确的顺序(否则另有说明)。 | | :—-: | —- |

一旦WebServerFactory可以使用定制程序访问,就可以使用它来配置特定的部分,例如连接器,服务器资源或服务器本身-全部使用服务器特定的API。
此外,Spring Boot还提供:

服务器 Servlet堆栈 反应堆
雄猫 TomcatServletWebServerFactory TomcatReactiveWebServerFactory
码头 JettyServletWebServerFactory JettyReactiveWebServerFactory
底拖 UndertowServletWebServerFactory UndertowReactiveWebServerFactory
反应堆 不适用 NettyReactiveWebServerFactory

作为最后的选择,您还可以声明自己的WebServerFactorybean,它将覆盖Spring Boot提供的bean。这样做时,自动配置的定制程序仍会应用到您的定制工厂,因此请谨慎使用该选项。

3.10。将Servlet,过滤器或侦听器添加到应用程序

在一个servlet栈的应用,即用spring-boot-starter-web,有两种方法可以添加ServletFilterServletContextListener,和由Servlet API到您的应用程序支持的其他听众:

  • 使用Spring Bean添加Servlet,过滤器或侦听器
  • 使用类路径扫描添加Servlet,过滤器和侦听器

    3.10.1。使用Spring Bean添加Servlet,过滤器或侦听器

    要添加ServletFilter或servlet*Listener使用的Spring bean,你必须提供一个@Bean它的定义。当您要注入配置或依赖项时,这样做非常有用。但是,您必须非常小心,以免引起过多其他bean的急切初始化,因为必须在应用程序生命周期的早期就将它们安装在容器中。(例如,让它们依赖于您的DataSource或JPA配置不是一个好主意。)您可以通过在第一次使用bean时而不是在初始化时进行延迟初始化来解决这些限制。
    对于FiltersServlets,您还可以通过添加FilterRegistrationBeanServletRegistrationBean代替基础组件或在基础组件之外添加映射和init参数。
如果dispatcherType在过滤器注册上未指定no ,REQUEST则使用。这与Servlet规范的默认调度程序类型一致。

像其他任何Spring bean一样,您可以定义Servlet过滤器bean的顺序。请确保检查“ spring-boot-features.html ”部分。

禁用Servlet或过滤器的注册

正如前面所述,任何ServletFilter豆与servlet容器自动注册。要禁用特定FilterServletbean的注册,请为其创建注册bean并将其标记为已禁用,如以下示例所示:

  1. @Bean
  2. public FilterRegistrationBean registration(MyFilter filter) {
  3. FilterRegistrationBean registration = new FilterRegistrationBean(filter);
  4. registration.setEnabled(false);
  5. return registration;
  6. }

3.10.2。使用类路径扫描添加Servlet,过滤器和侦听器

@WebServlet,,@WebFilter和带@WebListener注释的类可以通过向注释一个@Configuration@ServletComponentScan并指定包含要注册的组件的包来自动向嵌入式servlet容器注册。默认情况下,@ServletComponentScan从带注释的类的包进行扫描。

3.11。配置访问日志

可以通过它们各自的名称空间为Tomcat,Undertow和Jetty配置访问日志。
例如,以下设置使用自定义模式记录对Tomcat的访问。
特性
Yaml

  1. server:
  2. tomcat:
  3. basedir: "my-tomcat"
  4. accesslog:
  5. enabled: true
  6. pattern: "%t %a %r %s (%D ms)"
日志的默认位置是logs相对于Tomcat基本目录的目录。默认情况下,该logs目录是一个临时目录,因此您可能需要修复Tomcat的基本目录或为日志使用绝对路径。在前面的示例中,日志my-tomcat/logs相对于应用程序的工作目录可用。

可以用类似的方式配置Undertow的访问日志,如以下示例所示:
特性
Yaml

  1. server:
  2. undertow:
  3. accesslog:
  4. enabled: true
  5. pattern: "%t %a %r %s (%D ms)"

日志存储在logs相对于应用程序工作目录的目录中。您可以通过设置server.undertow.accesslog.dir属性来自定义此位置。
最后,Jetty的访问日志也可以配置如下:
特性
Yaml

  1. server:
  2. jetty:
  3. accesslog:
  4. enabled: true
  5. filename: "/var/log/jetty-access.log"

默认情况下,日志重定向到System.err。有关更多详细信息,请参见Jetty文档。

3.12。在前端代理服务器后面运行

如果您的应用程序是在代理,负载均衡器之后或在云中运行的,则请求信息(例如主机,端口,方案等)可能会随之变化。您的应用程序可能正在运行10.10.10.10:8080,但是HTTP客户端只能看到example.org
RFC7239“转发标头”定义了ForwardedHTTP标头;代理可以使用此标头来提供有关原始请求的信息。您可以将应用程序配置为读取这些标头,并在创建链接并将其发送到HTTP 302响应,JSON文档或HTML页面中的客户端时自动使用该信息。还有一些非标准的标题,如:X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-Ssl,和X-Forwarded-Prefix
如果代理添加常用X-Forwarded-ForX-Forwarded-Proto标题,设置server.forward-headers-strategyNATIVE足以支持这些。使用此选项,Web服务器本身就本身支持此功能。您可以查看他们的特定文档以了解特定行为。
如果这还不够,Spring框架将提供ForwardedHeaderFilter。通过将设置server.forward-headers-strategy为,可以将其注册为应用程序中的Servlet过滤器FRAMEWORK

如果您正在使用Tomcat并在代理处终止SSL,server.tomcat.redirect-context-root则应将其设置为false。这样可以在X-Forwarded-Proto执行任何重定向之前兑现标头。
如果您的应用程序在Cloud Foundry或Heroku中运行,则该server.forward-headers-strategy属性默认为NATIVE。在所有其他情况下,它默认为NONE

3.12.1。自定义Tomcat的代理配置

如果使用Tomcat,则可以另外配置用于承载“转发的”信息的标头名称,如以下示例所示:
特性
Yaml

  1. server:
  2. tomcat:
  3. remoteip:
  4. remote-ip-header: "x-your-remote-ip-header"
  5. protocol-header: "x-your-protocol-header"

Tomcat还配置有默认正则表达式,该正则表达式与要信任的内部代理匹配。默认情况下,IP地址10/8192.168/16169.254/16并且127/8是值得信赖的。您可以通过在上添加一个条目来自定义阀门的配置application.properties,如以下示例所示:
特性
Yaml

  1. server:
  2. tomcat:
  3. remoteip:
  4. internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"
您可以通过将设置internal-proxies为空来信任所有代理(但在生产环境中不要这样做)。

您可以完全RemoteIpValve关闭Tomcat的配置,方法是关闭自动开关(为此,请设置server.forward-headers-strategy=NONE)并使用WebServerFactoryCustomizerBean添加新的Valve实例。

3.13。使用Tomcat启用多个连接器

您可以在中添加,org.apache.catalina.connector.ConnectorTomcatServletWebServerFactory允许多个连接器,包括HTTP和HTTPS连接器,如以下示例所示:

  1. @Bean
  2. public WebServerFactoryCustomizer<TomcatServletWebServerFactory> sslConnectorCustomizer() {
  3. return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createSslConnector());
  4. }
  5. private Connector createSslConnector() {
  6. Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
  7. Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
  8. try {
  9. URL keystore = ResourceUtils.getURL("keystore");
  10. URL truststore = ResourceUtils.getURL("truststore");
  11. connector.setScheme("https");
  12. connector.setSecure(true);
  13. connector.setPort(8443);
  14. protocol.setSSLEnabled(true);
  15. protocol.setKeystoreFile(keystore.toString());
  16. protocol.setKeystorePass("changeit");
  17. protocol.setTruststoreFile(truststore.toString());
  18. protocol.setTruststorePass("changeit");
  19. protocol.setKeyAlias("apitester");
  20. return connector;
  21. }
  22. catch (IOException ex) {
  23. throw new IllegalStateException("Fail to create ssl connector", ex);
  24. }
  25. }

3.14。使用Tomcat的LegacyCookieProcessor

默认情况下,Spring Boot使用的嵌入式Tomcat不支持Cookie格式的“版本0”,因此您可能会看到以下错误:
java.lang.IllegalArgumentException:Cookie值中存在无效字符[32]
如果可能的话,您应该考虑将代码更新为仅存储符合以后Cookie规范的值。但是,如果无法更改cookie的编写方式,则可以将Tomcat配置为使用LegacyCookieProcessor。要切换到LegacyCookieProcessor,请使用WebServerFactoryCustomizer添加了的Bean TomcatContextCustomizer,如以下示例所示:

  1. @Bean
  2. public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
  3. return (factory) -> factory
  4. .addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
  5. }

3.15。启用Tomcat的MBean注册表

默认情况下,嵌入式Tomcat的MBean注册表是禁用的。这样可以最大程度地减少Tomcat的内存占用。例如,如果要使用Tomcat的MBean,以便可以将它们用于通过Micrometer公开指标,则必须使用该server.tomcat.mbeanregistry.enabled属性,如以下示例所示:
特性
Yaml

  1. server:
  2. tomcat:
  3. mbeanregistry:
  4. enabled: true

3.16。使用Undertow启用多个侦听器

向中添加一个UndertowBuilderCustomizerUndertowServletWebServerFactory并向中添加一个侦听器Builder,如以下示例所示:

  1. @Bean
  2. public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() {
  3. return (factory) -> {
  4. factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
  5. @Override
  6. public void customize(Builder builder) {
  7. builder.addHttpListener(8080, "0.0.0.0");
  8. }
  9. });
  10. };
  11. }

3.17。使用@ServerEndpoint创建WebSocket端点

如果要在使用@ServerEndpoint嵌入式容器的Spring Boot应用程序中使用,必须声明一个single ServerEndpointExporter @Bean,如以下示例所示:

  1. @Bean
  2. public ServerEndpointExporter serverEndpointExporter() {
  3. return new ServerEndpointExporter();
  4. }

前面示例中显示的bean将所有带@ServerEndpoint注释的bean注册到基础WebSocket容器中。当部署到独立servlet容器时,此角色由servlet容器初始化程序执行,并且ServerEndpointExporter不需要bean。

4. Spring MVC

Spring Boot有许多启动器,其中包括Spring MVC。请注意,某些入门者包括对Spring MVC的依赖,而不是直接包含它。本部分回答有关Spring MVC和Spring Boot的常见问题。

4.1。编写JSON REST服务

@RestController只要Jackson2在类路径上,Spring Boot应用程序中的任何Spring默认情况下都应呈现JSON响应,如以下示例所示:

  1. @RestController
  2. public class MyController {
  3. @RequestMapping("/thing")
  4. public MyThing thing() {
  5. return new MyThing();
  6. }
  7. }

只要MyThing可以由Jackson2序列化(对于普通的POJO或Groovy对象为true),则[localhost:8080/thing](http://localhost:8080/thing)默认情况下会为其提供JSON表示。请注意,在浏览器中,有时您可能会看到XML响应,因为浏览器倾向于发送更喜欢XML的接受标头。

4.2。编写XML REST服务

如果jackson-dataformat-xml类路径上具有Jackson XML扩展名(),则可以使用它来呈现XML响应。我们用于JSON的先前示例可以正常工作。要使用Jackson XML渲染器,请将以下依赖项添加到您的项目中:

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.dataformat</groupId>
  3. <artifactId>jackson-dataformat-xml</artifactId>
  4. </dependency>

如果无法使用Jackson的XML扩展名而可以使用JAXB,则可以将XMLMyThing注释为@XmlRootElement,并具有附加要求,如以下示例所示:

  1. @XmlRootElement
  2. public class MyThing {
  3. private String name;
  4. // .. getters and setters
  5. }

JAXB仅在Java 8中是开箱即用的。如果您使用的是较新的Java版本,请在项目中添加以下依赖项:

  1. <dependency>
  2. <groupId>org.glassfish.jaxb</groupId>
  3. <artifactId>jaxb-runtime</artifactId>
  4. </dependency>
要使服务器呈现XML而不是JSON,您可能必须发送Accept: text/xml标头(或使用浏览器)。

4.3。自定义Jackson ObjectMapper

Spring MVC(客户端和服务器端)用于HttpMessageConverters协商HTTP交换中的内容转换。如果Jackson在类路径中,则您已经获得所提供的默认转换器,该转换器Jackson2ObjectMapperBuilder的实例已为您自动配置。
ObjectMapper(或XmlMapper为杰克逊XML转换器)实例(默认创建)具有以下定义的属性:

  • MapperFeature.DEFAULT_VIEW_INCLUSION 被禁用
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 被禁用
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 被禁用

Spring Boot还具有一些功能,可以更轻松地自定义此行为。
您可以使用环境配置ObjectMapperXmlMapper实例。Jackson提供了丰富的开/关功能套件,可用于配置其处理的各个方面。在六个枚举(在Jackson中)中描述了这些功能,这些枚举映射到环境中的属性:

枚举 财产 价值观
com.fasterxml.jackson.databind.DeserializationFeature spring.jackson.deserialization.<feature_name> truefalse
com.fasterxml.jackson.core.JsonGenerator.Feature spring.jackson.generator.<feature_name> truefalse
com.fasterxml.jackson.databind.MapperFeature spring.jackson.mapper.<feature_name> truefalse
com.fasterxml.jackson.core.JsonParser.Feature spring.jackson.parser.<feature_name> truefalse
com.fasterxml.jackson.databind.SerializationFeature spring.jackson.serialization.<feature_name> truefalse
com.fasterxml.jackson.annotation.JsonInclude.Include spring.jackson.default-property-inclusion alwaysnon_nullnon_absentnon_defaultnon_empty

例如,要启用漂亮打印,请设置spring.jackson.serialization.indent_output=true。请注意,由于使用了宽松的绑定,的大小写indent_output不必与相应的枚举常量的大小写匹配INDENT_OUTPUT
这种基于环境的配置适用于自动配置的Jackson2ObjectMapperBuilderBean,并且适用于使用构建器创建的任何映射器,包括自动配置的ObjectMapperBean。
上下文Jackson2ObjectMapperBuilder可以由一个或多个Jackson2ObjectMapperBuilderCustomizerbean自定义。可以对此类定制器bean进行排序(Boot自己的定制器的顺序为0),从而可以在Boot定制之前和之后应用其他定制。
任何类型的bean都会com.fasterxml.jackson.databind.Module自动向自动配置中注册,Jackson2ObjectMapperBuilder并应用于ObjectMapper它创建的任何实例。当您向应用程序中添加新功能时,这提供了一种用于贡献自定义模块的全局机制。
如果要ObjectMapper完全替换默认值,请定义@Bean该类型的a并将其标记为,@Primary或者,如果您更喜欢基于构建器的方法,请定义一个Jackson2ObjectMapperBuilder @Bean。请注意,无论哪种情况,这样做都会禁用的所有自动配置ObjectMapper
如果提供任何@Beanstype MappingJackson2HttpMessageConverter,它们将替换MVC配置中的默认值。此外,HttpMessageConverters还提供了一种类型的便捷bean (如果使用默认的MVC配置,该bean始终可用)。它提供了一些有用的方法来访问默认的和用户增强的消息转换器。
请参阅“自定义@ResponseBody渲染”部分和WebMvcAutoConfiguration源代码以获取更多详细信息。

4.4。自定义@ResponseBody渲染

Spring用于HttpMessageConverters呈现@ResponseBody(或的响应@RestController)。您可以通过在Spring Boot上下文中添加适当类型的bean来贡献额外的转换器。如果您添加的bean的类型无论如何都是默认包含的(例如MappingJackson2HttpMessageConverterJSON转换),它将替换默认值。HttpMessageConverters提供了类型的便捷bean,如果您使用默认的MVC配置,它将始终可用。它提供了一些有用的方法来访问默认的和用户增强的消息转换器(例如,如果您想将它们手动注入到custom中,可能会很有用RestTemplate)。
与正常的MVC用法一样,WebMvcConfigurer您提供的任何bean也可以通过重写configureMessageConverters方法来贡献转换器。但是,与普通的MVC不同,您只能提供所需的其他转换器(因为Spring Boot使用相同的机制来提供其默认值)。最后,如果您通过提供自己的@EnableWebMvc配置选择退出Spring Boot的默认MVC配置,则可以完全控制并使用getMessageConvertersfrom手动进行所有操作WebMvcConfigurationSupport
请参阅WebMvcAutoConfiguration源代码以获取更多详细信息。

4.5。处理分段文件上传

Spring Boot包含Servlet 3 javax.servlet.http.PartAPI以支持上传文件。默认情况下,Spring Boot用单个请求将Spring MVC配置为每个文件最大大小为1MB,最大文件数据为10MB。您可以覆盖这些值,使用中间类提供/tmp的属性将中间数据存储到的位置(例如,存储到目录)以及将数据刷新到磁盘的阈值MultipartProperties。例如,如果您要指定文件不受限制,请将spring.servlet.multipart.max-file-size属性设置为-1
当您想在Spring MVC控制器处理程序方法中将多部分编码的文件数据作为带@RequestParam注释的类型的参数来接收时,多部分支持会很有帮助MultipartFile
有关MultipartAutoConfiguration更多详细信息,请参见源。

建议使用容器的内置支持进行分段上传,而不要引入其他依赖项,例如Apache Commons File Upload。

4.6。关闭Spring MVC DispatcherServlet

默认情况下,所有内容均从应用程序的根目录(/)提供。如果您希望映射到其他路径,则可以如下配置:
特性
Yaml

  1. spring:
  2. mvc:
  3. servlet:
  4. path: "/acme"

如果您有其他servlet,则可以声明一个或@Bean类型,然后Spring Boot会将它们透明地注册到容器。由于Servlet是通过这种方式注册的,因此可以将它们映射到的子上下文而无需调用它。Servlet``ServletRegistrationBean``DispatcherServlet
配置DispatcherServlet您自己是不寻常的,但是如果您确实需要这样做,则还必须提供一个@BeantypeDispatcherServletPath以提供自定义的路径DispatcherServlet

4.7。关闭默认的MVC配置

完全控制MVC配置的最简单方法是为您自己@Configuration提供@EnableWebMvc注释。这样做会使您掌握所有MVC配置。

4.8。自定义ViewResolvers

AViewResolver是Spring MVC的核心组件,将视图名称转换@Controller为实际的View实现。请注意,ViewResolvers它主要用于UI应用程序,而不是REST风格的服务(aView不用于呈现a @ResponseBody)。有很多实现ViewResolver可供选择,Spring本身对是否应使用哪个没有意见。另一方面,Spring Boot会根据您在类路径和应用程序上下文中找到的内容为您安装一个或两个。会DispatcherServlet使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器,直到获得结果。如果添加自己的解析器,则必须知道其顺序以及解析器的添加位置。
WebMvcAutoConfiguration将以下内容添加ViewResolvers到您的上下文中:

  • 一个InternalResourceViewResolver名为“defaultViewResolver”。此文件查找可以通过使用渲染的物理资源DefaultServlet(包括静态资源和JSP页面,如果使用的话)。它将一个前缀和一个后缀应用于视图名称,然后在Servlet上下文中查找具有该路径的物理资源(默认值均为空,但可以通过spring.mvc.view.prefix和进行外部配置访问spring.mvc.view.suffix)。您可以通过提供相同类型的bean来覆盖它。
  • 一个BeanNameViewResolver名为“beanNameViewResolver”。这是视图解析器链的有用成员,可以拾取与View被解析名称相同的所有bean 。不必重写或替换它。
  • ContentNegotiatingViewResolver仅当实际存在类型bean的情况下,才添加一个名为“ viewResolver”的视图View。这是一个“主”解析器,委派给所有其他解析器,并尝试查找与客户端发送的“ Accept” HTTP标头匹配的内容。有一个有用的博客ContentNegotiatingViewResolver,您可能想学习以了解更多信息,并且您也可以查看源代码以获取详细信息。您可以ContentNegotiatingViewResolver通过定义一个名为“ viewResolver”的bean来关闭自动配置。
  • 如果您使用Thymeleaf,则还有一个ThymeleafViewResolver名为“ thymeleafViewResolver”。它通过在视图名称前后加上前缀和后缀来查找资源。前缀为spring.thymeleaf.prefix,后缀为spring.thymeleaf.suffix。前缀和后缀的值分别默认为“ classpath:/ templates /”和“ .html”。您可以ThymeleafViewResolver通过提供相同名称的bean来覆盖。
  • 如果您使用FreeMarker,则还有一个FreeMarkerViewResolver名为“ freeMarkerViewResolver”的文件。它spring.freemarker.templateLoaderPath通过在视图名称前加上前缀和后缀来在加载程序路径(已外部化并具有默认值’classpath:/ templates /‘)中查找资源。前缀被外部spring.freemarker.prefix化为,后缀被外部化为spring.freemarker.suffix。前缀和后缀的默认值分别为空和’.ftlh’。您可以FreeMarkerViewResolver通过提供相同名称的bean来覆盖。
  • 如果您使用Groovy模板(实际上,如果groovy-templates在类路径中),则还具有一个GroovyMarkupViewResolver名为“ groovyMarkupViewResolver”的名称。它通过在视图名称前加上前缀和后缀(spring.groovy.template.prefix并扩展为和spring.groovy.template.suffix)来在加载程序路径中查找资源。前缀和后缀分别具有默认值’classpath:/ templates /‘和’.tpl’。您可以GroovyMarkupViewResolver通过提供相同名称的bean来覆盖。
  • 如果您使用Moustache,则还有一个MustacheViewResolver名为“ mustacheViewResolver”的文件。它通过在视图名称前后加上前缀和后缀来查找资源。前缀为spring.mustache.prefix,后缀为spring.mustache.suffix。前缀和后缀的值分别默认为“ classpath:/ templates /”和“ .mustache”。您可以MustacheViewResolver通过提供相同名称的bean来覆盖。

有关更多详细信息,请参见以下部分:

  • WebMvcAutoConfiguration
  • ThymeleafAutoConfiguration
  • FreeMarkerAutoConfiguration
  • GroovyTemplateAutoConfiguration

    5.使用Spring Security进行测试

    Spring Security提供了对以特定用户身份运行测试的支持。例如,下面的代码段中的测试将与具有该ADMIN角色的经过身份验证的用户一起运行。
    1. @Test
    2. @WithMockUser(roles="ADMIN")
    3. public void requestProtectedUrlWithUser() throws Exception {
    4. mvc
    5. .perform(get("/"))
    6. ...
    7. }
    Spring Security提供了与Spring MVC Test的全面集成,并且在使用@WebMvcTestslice和测试控制器时也可以使用它MockMvc
    有关Spring Security的测试支持的更多详细信息,请参阅Spring Security的参考文档

    6.球衣

    6.1。使用Spring Security保护Jersey端点

    可以使用Spring Security来保护基于Jersey的Web应用程序,其方式与用来保护基于Spring MVC的Web应用程序的方式几乎相同。但是,如果您想在Jersey上使用Spring Security的方法级安全性,则必须将Jersey配置为使用setStatus(int)pretty sendError(int)。这可以防止Jersey在Spring Security有机会向客户端报告身份验证或授权失败之前提交响应。
    jersey.config.server.response.setStatusOverSendError属性必须true在应用程序的ResourceConfigBean上设置为,如以下示例所示:
    1. @Component
    2. public class JerseyConfig extends ResourceConfig {
    3. public JerseyConfig() {
    4. register(Endpoint.class);
    5. setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
    6. }
    7. }

    6.2。与另一个Web框架一起使用Jersey

    要将Jersey与其他Web框架(例如Spring MVC)一起使用,应对其进行配置,以便它将允许其他框架处理无法处理的请求。首先,通过将spring.jersey.type应用程序属性配置为值,将Jersey配置为使用过滤器而不是Servlet filter。其次,将您的服务器配置ResourceConfig为转发可能导致404的请求,如以下示例所示。
    1. @Component
    2. public class JerseyConfig extends ResourceConfig {
    3. public JerseyConfig() {
    4. register(Endpoint.class);
    5. property(ServletProperties.FILTER_FORWARD_ON_404, true);
    6. }
    7. }

    7. HTTP客户端

    Spring Boot提供了许多可与HTTP客户端一起使用的启动器。本节回答与使用它们有关的问题。

    7.1。配置RestTemplate使用代理

    spring-boot-features.html中所述,您可以使用RestTemplateCustomizerwithRestTemplateBuilder来构建自定义的RestTemplate。这是创建RestTemplate配置为使用代理的推荐方法。
    代理配置的确切详细信息取决于所使用的基础客户端请求工厂。以下示例使用进行配置HttpComponentsClientRequestFactory,该HttpClient代理使用除192.168.0.5以下主机之外的所有主机的代理:
    1. static class ProxyCustomizer implements RestTemplateCustomizer {
    2. @Override
    3. public void customize(RestTemplate restTemplate) {
    4. HttpHost proxy = new HttpHost("proxy.example.com");
    5. HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
    6. @Override
    7. public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context)
    8. throws HttpException {
    9. if (target.getHostName().equals("192.168.0.5")) {
    10. return null;
    11. }
    12. return super.determineProxy(target, request, context);
    13. }
    14. }).build();
    15. restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    16. }
    17. }

    7.2。配置基于Reactor Netty的WebClient使用的TcpClient

    当Reactor Netty在类路径上时,将WebClient自动配置基于Reactor Netty的文件。要自定义客户端对网络连接的处理,请提供一个ClientHttpConnectorbean。以下示例配置60秒的连接超时并添加ReadTimeoutHandler
    1. @Bean
    2. ClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) {
    3. HttpClient httpClient = HttpClient.create(resourceFactory.getConnectionProvider())
    4. .runOn(resourceFactory.getLoopResources()).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
    5. .doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60)));
    6. return new ReactorClientHttpConnector(httpClient);
    7. }
    | | 请注意对ReactorResourceFactory连接提供程序和事件循环资源的使用。这确保了用于服务器接收请求和客户端发出请求的资源的有效共享。 | | :—-: | —- |

8.记录

除了通常由Spring Framework的spring-jcl模块提供的Commons Logging API之外,Spring Boot没有强制性的日志记录依赖项。要使用Logback,您需要将其包括spring-jcl在类路径中。推荐的启动方式是通过启动器,这完全取决于spring-boot-starter-logging。对于Web应用程序,您仅需要spring-boot-starter-web,因为它暂时依赖于日志记录启动器。如果使用Maven,则以下依赖项会为您添加日志记录:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>

Spring Boot有一个LoggingSystem抽象,它试图根据类路径的内容来配置日志记录。如果可以使用Logback,则它是首选。
如果您需要对日志记录进行的唯一更改是设置各种记录器的级别,则可以application.properties使用“ logging.level”前缀来进行设置,如以下示例所示:
特性
Yaml

  1. logging:
  2. level:
  3. org.springframework.web: "debug"
  4. org.hibernate: "error"

您还可以使用来设置日志写入文件的位置(除了控制台)logging.file.name
要配置日志记录系统的更细粒度的设置,您需要使用所支持的本机配置格式LoggingSystem。默认情况下,Spring Boot从系统的默认位置(例如classpath:logback.xmlLogback)拾取本地配置,但是您可以使用logging.config属性设置配置文件的位置。

8.1。配置登录以进行日志记录

如果您需要将自定义设置应用于Logback之外的自定义设置,则application.properties需要添加标准的Logback配置文件。您可以将logback.xml文件添加到类路径的根目录中,以供登录后查找。logback-spring.xml如果要使用Spring Boot Logback扩展,也可以使用。

Logback文档有一个专用部分,其中详细介绍了配置

Spring Boot提供了许多included来自您自己的配置的logback配置。这些包括旨在允许重新应用某些常见的Spring Boot约定。
以下文件提供了org/springframework/boot/logging/logback/

  • defaults.xml -提供转换规则,模式属性和通用记录器配置。
  • console-appender.xml-ConsoleAppender使用添加CONSOLE_LOG_PATTERN
  • file-appender.xml-RollingFileAppender使用FILE_LOG_PATTERN和并ROLLING_FILE_NAME_PATTERN通过适当的设置添加。

此外,base.xml还提供了一个旧文件以与早期版本的Spring Boot兼容。
典型的自定义logback.xml文件如下所示:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3. <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
  4. <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
  5. <root level="INFO">
  6. <appender-ref ref="CONSOLE" />
  7. </root>
  8. <logger name="org.springframework.web" level="DEBUG"/>
  9. </configuration>

您的登录配置文件也可以利用LoggingSystem为您创建的System属性:

  • ${PID}:当前进程ID。
  • ${LOG_FILE}:是否logging.file.name在Boot的外部配置中设置。
  • ${LOG_PATH}:是否logging.file.path在Boot的外部配置中设置了(表示要存放日志文件的目录)。
  • ${LOG_EXCEPTION_CONVERSION_WORD}:是否logging.exception-conversion-word在Boot的外部配置中设置。
  • ${ROLLING_FILE_NAME_PATTERN}:是否logging.pattern.rolling-file-name在Boot的外部配置中设置。

通过使用自定义的Logback转换器,Spring Boot还可以在控制台上提供一些不错的ANSI颜色终端输出(但不在日志文件中)。看到CONSOLE_LOG_PATTERNdefaults.xml一个示例配置。
如果Groovy在类路径上,那么您也应该能够配置Logback logback.groovy。如果存在,则优先考虑此设置。

Groovy配置不支持Spring扩展。logback-spring.groovy不会检测到任何文件。

8.1.1。配置仅文件输出的Logback

如果要禁用控制台日志记录并且仅将输出写入文件,则需要一个logback-spring.xml导入file-appender.xml但不导入的自定义console-appender.xml,如以下示例所示:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3. <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  4. <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
  5. <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
  6. <root level="INFO">
  7. <appender-ref ref="FILE" />
  8. </root>
  9. </configuration>

您还需要添加logging.file.nameapplication.properties或中application.yaml,如以下示例所示:
特性
Yaml

  1. logging:
  2. file:
  3. name: "myapplication.log"

8.2。配置Log4j进行日志记录

如果Spring Boot在类路径上,则它支持Log4j 2进行日志记录配置。如果使用启动器来组装依赖项,则必须排除Logback,然后改为包括log4j 2。如果您不使用启动器,则spring-jcl除了Log4j 2外,还需要(至少)提供。
推荐的路径是通过启动器,即使它需要一些摇晃。以下示例显示了如何在Maven中设置启动器:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter</artifactId>
  8. <exclusions>
  9. <exclusion>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-logging</artifactId>
  12. </exclusion>
  13. </exclusions>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-log4j2</artifactId>
  18. </dependency>

以下示例显示了在Gradle中设置启动器的一种方法:

  1. dependencies {
  2. compile 'org.springframework.boot:spring-boot-starter-web'
  3. }
  4. configurations.all {
  5. resolutionStrategy.dependencySubstitution.all { dependency ->
  6. if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.module == 'spring-boot-starter-logging') {
  7. dependency.useTarget("org.springframework.boot:spring-boot-starter-log4j2:$dependency.requested.version", 'Use Log4j2 instead of Logback')
  8. }
  9. }
  10. }
  11. }
Log4j入门人员将依赖关系汇总在一起,以满足常见的日志记录要求(例如使用Tomcat,java.util.logging但使用Log4j 2配置输出)。
为了确保将使用进行的调试日志记录java.util.logging路由到Log4j 2中,请将系统属性设置为,以配置其JDK日志记录适配器java.util.logging.manager``org.apache.logging.log4j.jul.LogManager

8.2.1。使用YAML或JSON配置Log4j 2

除了默认的XML配置格式外,Log4j 2还支持YAML和JSON配置文件。要将Log4j 2配置为使用备用配置文件格式,请将适当的依赖项添加到类路径,并命名配置文件以匹配您选择的文件格式,如以下示例所示:

格式 依存关系 档案名称
YAML com.fasterxml.jackson.core:jackson-databind + com.fasterxml.jackson.dataformat:jackson-dataformat-yaml log4j2.yaml + log4j2.yml
JSON格式 com.fasterxml.jackson.core:jackson-databind log4j2.json + log4j2.jsn

9.资料存取

Spring Boot包含许多用于处理数据源的启动器。本节回答与这样做有关的问题。

9.1。配置自定义数据源

要配置自己的DataSource,请在配置中定义@Bean该类型的。Spring Boot可以DataSource在任何需要重用的地方重复使用,包括数据库初始化。如果您需要外部化某些设置,则可以将其绑定DataSource到环境(请参阅“ spring-boot-features.html ”)。
以下示例显示如何在Bean中定义数据源:

  1. @Bean
  2. @ConfigurationProperties(prefix="app.datasource")
  3. public DataSource dataSource() {
  4. return new FancyDataSource();
  5. }

以下示例显示如何通过设置属性来定义数据源:
特性
Yaml

  1. app:
  2. datasource:
  3. url: "jdbc:h2:mem:mydb"
  4. username: "sa"
  5. pool-size: 30

假设您FancyDataSource具有URL,用户名和池大小的常规JavaBean属性,则在将设置DataSource用于其他组件之前,将自动绑定这些设置。常规的数据库初始化也会发生(因此的相关子集spring.datasource.*仍可以与您的自定义配置一起使用)。
Spring Boot还提供了一个名为的实用程序生成器类,该类DataSourceBuilder可用于创建标准数据源之一(如果它位于类路径上)。构建器可以根据类路径中可用的内容来检测要使用的一个。它还基于JDBC URL自动检测驱动程序。
以下示例显示如何使用来创建数据源DataSourceBuilder

  1. @Bean
  2. @ConfigurationProperties("app.datasource")
  3. public DataSource dataSource() {
  4. return DataSourceBuilder.create().build();
  5. }

要使用that运行应用程序DataSource,您需要的只是连接信息。还可以提供特定于池的设置。有关更多详细信息,请检查将在运行时使用的实现。
以下示例显示如何通过设置属性来定义JDBC数据源:
特性
Yaml

  1. app:
  2. datasource:
  3. url: "jdbc:mysql://localhost/test"
  4. username: "dbuser"
  5. password: "dbpass"
  6. pool-size: 30

但是,有一个陷阱。由于未公开连接池的实际类型,因此在自定义元数据中不会生成任何键,DataSource并且在IDE中也无法完成操作(因为该DataSource接口未公开任何属性)。另外,如果您碰巧在类路径上有Hikari,则此基本设置将不起作用,因为Hikari没有url属性(但确实具有jdbcUrl属性)。在这种情况下,您必须按照以下方式重写配置:
特性
Yaml

  1. app:
  2. datasource:
  3. jdbc-url: "jdbc:mysql://localhost/test"
  4. username: "dbuser"
  5. password: "dbpass"
  6. pool-size: 30

您可以通过强制连接池使用并返回专用的实现而不是来解决此问题DataSource。您不能在运行时更改实现,但是选项列表将是明确的。
下面的示例演示如何创建一个HikariDataSource具有DataSourceBuilder

  1. @Bean
  2. @ConfigurationProperties("app.datasource")
  3. public HikariDataSource dataSource() {
  4. return DataSourceBuilder.create().type(HikariDataSource.class).build();
  5. }

您甚至可以利用DataSourceProperties为您服务的功能,即通过提供默认的嵌入式数据库(如果没有提供URL的话)为用户提供明智的用户名和密码,从而走得更远。您可以轻松地DataSourceBuilder从任何DataSourceProperties对象的状态初始化a ,因此您还可以注入Spring Boot自动创建的DataSource。然而,这将配置分为两个命名空间:urlusernamepasswordtype,和driverspring.datasource和您的自定义命名空间中的其余部分(app.datasource)。为避免这种情况,可以DataSourceProperties在自定义名称空间上重新定义一个自定义,如以下示例所示:

  1. @Bean
  2. @Primary
  3. @ConfigurationProperties("app.datasource")
  4. public DataSourceProperties dataSourceProperties() {
  5. return new DataSourceProperties();
  6. }
  7. @Bean
  8. @ConfigurationProperties("app.datasource.configuration")
  9. public HikariDataSource dataSource(DataSourceProperties properties) {
  10. return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
  11. }

默认情况下,此设置使您与Spring Boot为您所做的同步,不同的是,已选择(通过代码)专用的连接池,并且其设置在app.datasource.configuration子名称空间中公开。因为DataSourceProperties正在为您处理url/jdbcUrl转换,所以可以按以下方式配置它:
特性
Yaml

  1. app:
  2. datasource:
  3. url: "jdbc:mysql://localhost/test"
  4. username: "dbuser"
  5. password: "dbpass"
  6. configuration:
  7. maximum-pool-size: 30
Spring Boot会将Hikari特定的设置公开给spring.datasource.hikari。本示例使用更通用的configuration子名称空间,因为该示例不支持多个数据源实现。
由于您的自定义配置选择与Hikari一起使用,app.datasource.type因此无效。实际上,构建器会使用您可以在其中设置的任何值进行初始化,然后由调用覆盖.type()

有关更多详细信息,请参见“ Spring Boot功能”部分中的“ spring-boot-features.html ”和DataSourceAutoConfiguration该类。

9.2。配置两个数据源

如果需要配置多个数据源,则可以应用上一节中介绍的相同技巧。但是,您必须将其中一个DataSource实例标记为@Primary,因为将来各种自动配置都希望能够按类型获取一个。
如果您创建自己的DataSource,则自动配置将退出。在以下示例中,我们提供与自动配置在主数据源上提供的功能完全相同的功能集:

  1. @Bean
  2. @Primary
  3. @ConfigurationProperties("app.datasource.first")
  4. public DataSourceProperties firstDataSourceProperties() {
  5. return new DataSourceProperties();
  6. }
  7. @Bean
  8. @Primary
  9. @ConfigurationProperties("app.datasource.first.configuration")
  10. public HikariDataSource firstDataSource() {
  11. return firstDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
  12. }
  13. @Bean
  14. @ConfigurationProperties("app.datasource.second")
  15. public BasicDataSource secondDataSource() {
  16. return DataSourceBuilder.create().type(BasicDataSource.class).build();
  17. }
firstDataSourceProperties必须标记为,@Primary以便数据库初始化程序功能使用您的副本(如果使用初始化程序)。

这两个数据源也都必须进行高级定制。例如,您可以按以下方式配置它们:
特性
Yaml

  1. app:
  2. datasource:
  3. first:
  4. url: "jdbc:mysql://localhost/first"
  5. username: "dbuser"
  6. password: "dbpass"
  7. configuration:
  8. maximum-pool-size: 30
  9. second:
  10. url: "jdbc:mysql://localhost/second"
  11. username: "dbuser"
  12. password: "dbpass"
  13. max-total: 30

您也可以将相同的概念应用于辅助服务器DataSource,如以下示例所示:

  1. @Bean
  2. @Primary
  3. @ConfigurationProperties("app.datasource.first")
  4. public DataSourceProperties firstDataSourceProperties() {
  5. return new DataSourceProperties();
  6. }
  7. @Bean
  8. @Primary
  9. @ConfigurationProperties("app.datasource.first.configuration")
  10. public HikariDataSource firstDataSource() {
  11. return firstDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
  12. }
  13. @Bean
  14. @ConfigurationProperties("app.datasource.second")
  15. public DataSourceProperties secondDataSourceProperties() {
  16. return new DataSourceProperties();
  17. }
  18. @Bean
  19. @ConfigurationProperties("app.datasource.second.configuration")
  20. public BasicDataSource secondDataSource() {
  21. return secondDataSourceProperties().initializeDataSourceBuilder().type(BasicDataSource.class).build();
  22. }

上面的示例在自定义名称空间上配置两个数据源,其逻辑与Spring Boot在自动配置中使用的逻辑相同。请注意,每个configuration子名称空间都根据所选实现提供高级设置。

9.3。使用Spring数据仓库

Spring Data可以创建@Repository各种类型的接口的实现。只要Spring Boot@Repositories包含在类的同一包(或子包)中,Spring Boot就会为您处理所有这些操作@EnableAutoConfiguration
对于许多应用程序,您所需要做的就是在类路径上放置正确的Spring Data依赖项。spring-boot-starter-data-jpaJPA,spring-boot-starter-data-mongodbMongodb等都有一个。首先,创建一些存储库接口来处理您的@Entity对象。
Spring Boot会@Repository根据@EnableAutoConfiguration发现的内容尝试猜测您定义的位置。要获得更多控制权,请使用@EnableJpaRepositories注释(来自Spring Data JPA)。
有关Spring Data的更多信息,请参见Spring Data项目页面

9.4。将@Entity定义与Spring配置分开

Spring Boot会@Entity根据@EnableAutoConfiguration发现的内容尝试猜测您定义的位置。要获得更多控制,可以使用@EntityScan注释,如以下示例所示:

  1. @Configuration(proxyBeanMethods = false)
  2. @EnableAutoConfiguration
  3. @EntityScan(basePackageClasses=City.class)
  4. public class Application {
  5. //...
  6. }

9.5。配置JPA属性

Spring Data JPA已经提供了一些独立于供应商的配置选项(例如用于SQL日志记录的那些),并且Spring Boot公开了这些选项,还为Hibernate提供了一些其他选项作为外部配置属性。其中一些会根据上下文自动检测到,因此您不必进行设置。
spring.jpa.hibernate.ddl-auto是一种特殊情况,因为根据运行时条件,它具有不同的默认值。如果使用嵌入式数据库并且没有模式管理器(例如Liquibase或Flyway)正在处理DataSource,则默认为create-drop。在所有其他情况下,默认为none
JPA提供程序检测到要使用的方言。如果您想自己设置方言,请设置spring.jpa.database-platform属性。
以下示例显示了最常用的设置选项:
特性
Yaml

  1. spring:
  2. jpa:
  3. hibernate:
  4. naming:
  5. physical-strategy: "com.example.MyPhysicalNamingStrategy"
  6. show-sql: true

此外,创建spring.jpa.properties.*本地时,所有属性均作为常规JPA属性(前缀被去除)传递EntityManagerFactory

您需要确保在下面定义的名称spring.jpa.properties.*与您的JPA提供程序期望的名称完全匹配。Spring Boot不会尝试对这些条目进行任何形式的宽松绑定。
例如,如果要配置Hibernate的批处理大小,则必须使用spring.jpa.properties.hibernate.jdbc.batch_size。如果您使用其他形式,例如batchSizebatch-size,则Hibernate将不会应用该设置。
如果您需要对Hibernate属性应用高级自定义,请考虑HibernatePropertiesCustomizer在创建之前注册将被调用的bean EntityManagerFactory。这优先于自动配置应用的任何内容。

9.6。配置休眠命名策略

Hibernate使用两种不同的命名策略将名称从对象模型映射到相应的数据库名称。可以分别通过设置spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy属性来配置物理和隐式策略实现的标准类名。替代地,如果ImplicitNamingStrategyPhysicalNamingStrategy豆在应用程序上下文是可用的,Hibernate会被自动配置为使用它们。
默认情况下,Spring Boot使用配置物理命名策略SpringPhysicalNamingStrategy。此实现提供了与Hibernate 4相同的表结构:所有点都由下划线替换,骆驼套也由下划线替换。此外,默认情况下,所有表名均以小写形式生成。例如,一个TelephoneNumber实体被映射到telephone_number表。如果您的模式需要大小写混合的标识符,请定义一个自定义SpringPhysicalNamingStrategybean,如以下示例所示:

  1. @Bean
  2. SpringPhysicalNamingStrategy caseSensitivePhysicalNamingStrategy() {
  3. return new SpringPhysicalNamingStrategy() {
  4. @Override
  5. protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
  6. return false;
  7. }
  8. };
  9. }

如果您更喜欢使用Hibernate 5的默认设置,请设置以下属性:
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
另外,您可以配置以下bean:

  1. @Bean
  2. public PhysicalNamingStrategy physicalNamingStrategy() {
  3. return new PhysicalNamingStrategyStandardImpl();
  4. }

请参阅HibernateJpaAutoConfigurationJpaBaseConfiguration了解更多信息。

9.7。配置Hibernate二级缓存

可以为一系列缓存提供程序配置Hibernate二级缓存。与其将Hibernate配置为再次查找缓存提供程序,不如提供尽可能在上下文中可用的缓存提供程序。
要使用JCache做到这一点,首先要确保它org.hibernate:hibernate-jcache在类路径中可用。然后,添加一个HibernatePropertiesCustomizerbean,如以下示例所示:

  1. @Configuration(proxyBeanMethods = false)
  2. public class HibernateSecondLevelCacheExample {
  3. @Bean
  4. public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
  5. return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
  6. }
  7. }

该定制程序将配置Hibernate以CacheManager使其与应用程序使用的Hibernate相同。也可以使用单独的CacheManager实例。有关详细信息,请参阅《 Hibernate用户指南》

9.8。在Hibernate组件中使用依赖注入

默认情况下,Spring Boot注册使用的BeanContainer实现,BeanFactory以便转换器和实体侦听器可以使用常规依赖项注入。
您可以通过注册HibernatePropertiesCustomizer删除或更改hibernate.resource.beans.container属性的来禁用或调整此行为。

9.9。使用自定义EntityManagerFactory

要完全控制的配置EntityManagerFactory,您需要添加一个@Bean名为“ entityManagerFactory”的文件。如果存在这种类型的Bean,Spring Boot自动配置将关闭其实体管理器。

9.10。使用两个EntityManager

即使默认设置EntityManagerFactory可以正常工作,您也需要定义一个新的,否则,该类型的第二个bean的存在将关闭默认设置。您可以使用EntityManagerBuilderSpring Boot提供的帮助来创建一个。或者,您可以LocalContainerEntityManagerFactoryBean直接使用Spring ORM的Direct,如以下示例所示:

  1. // add two data sources configured as above
  2. @Bean
  3. public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
  4. EntityManagerFactoryBuilder builder) {
  5. return builder
  6. .dataSource(customerDataSource())
  7. .packages(Customer.class)
  8. .persistenceUnit("customers")
  9. .build();
  10. }
  11. @Bean
  12. public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
  13. EntityManagerFactoryBuilder builder) {
  14. return builder
  15. .dataSource(orderDataSource())
  16. .packages(Order.class)
  17. .persistenceUnit("orders")
  18. .build();
  19. }
当您为LocalContainerEntityManagerFactoryBean自己创建一个bean时,在创建自动配置的过程中应用的所有定制都将LocalContainerEntityManagerFactoryBean丢失。例如,在Hibernate的情况下,spring.jpa.hibernate前缀下的任何属性都不会自动应用于LocalContainerEntityManagerFactoryBean。如果您依靠这些属性来配置诸如命名策略或DDL模式之类的东西,则在创建LocalContainerEntityManagerFactoryBeanBean时将需要显式配置。另一方面,如果您使用自动配置来构建Bean ,则将自动应用EntityManagerFactoryBuilder通过所指定的应用于自动配置的属性。 spring.jpa.properties``EntityManagerFactoryBuilder``LocalContainerEntityManagerFactoryBean

上面的配置几乎可以独立工作。要完成图片,您还需要TransactionManagers为两者进行配置EntityManagers。如果将其中一个标记为@Primary,则可以JpaTransactionManager在Spring Boot中将其默认选中。另一个必须显式地注入到新实例中。另外,您也许可以使用跨这两者的JTA事务管理器。
如果使用Spring Data,则需要进行相应的配置@EnableJpaRepositories,如以下示例所示:

  1. @Configuration(proxyBeanMethods = false)
  2. @EnableJpaRepositories(basePackageClasses = Customer.class,
  3. entityManagerFactoryRef = "customerEntityManagerFactory")
  4. public class CustomerConfiguration {
  5. ...
  6. }
  7. @Configuration(proxyBeanMethods = false)
  8. @EnableJpaRepositories(basePackageClasses = Order.class,
  9. entityManagerFactoryRef = "orderEntityManagerFactory")
  10. public class OrderConfiguration {
  11. ...
  12. }

9.11。使用传统的persistence.xml文件

META-INF/persistence.xml默认情况下,Spring Boot不会搜索或使用。如果您喜欢使用传统的persistence.xml,则需要定义自己@Bean的类型LocalEntityManagerFactoryBean(ID为’entityManagerFactory’)并在其中设置持久性单元名称。
请参阅JpaBaseConfiguration以获取默认设置。

9.12。使用Spring Data JPA和Mongo存储库

Spring Data JPA和Spring Data Mongo都可以自动Repository为您创建实现。如果它们都存在于类路径中,则可能必须做一些额外的配置以告诉Spring Boot要创建哪个存储库。最明确的方法是使用标准的Spring数据@EnableJpaRepositories@EnableMongoRepositories注释并提供Repository接口的位置。
您还可以使用标记(spring.data.*.repositories.enabledspring.data.*.repositories.type)在外部配置中打开和关闭自动配置的存储库。这样做很有用,例如,在您要关闭Mongo存储库并仍使用自动配置的情况下MongoTemplate
其他自动配置的Spring Data存储库类型(Elasticsearch,Solr等)存在相同的障碍和相同的功能。要使用它们,请相应地更改注释和标志的名称。

9.13。定制Spring Data的Web支持

Spring Data提供了Web支持,简化了Web应用程序中Spring Data存储库的使用。Spring Boot在spring.data.web名称空间中提供了用于自定义其配置的属性。请注意,如果您使用的是Spring Data REST,则必须spring.data.rest改为使用名称空间中的属性。

9.14。将Spring数据存储库公开为REST端点

Repository如果已为应用程序启用了Spring MVC,Spring Data REST可以为您将实现公开为REST端点。
Spring Boot公开了一组有用的属性(来自spring.data.rest名称空间),用于自定义RepositoryRestConfiguration。如果需要提供其他定制,则应使用RepositoryRestConfigurerBean。

如果您未在custom上指定任何顺序RepositoryRestConfigurer,则该顺序将在一个Spring Boot在内部使用后运行。如果您需要指定一个订单,请确保它大于0。

9.15。配置由JPA使用的组件

如果要配置JPA使用的组件,则需要确保在JPA之前初始化该组件。当组件被自动配置后,Spring Boot会为您处理。例如,当自动配置Flyway时,会将Hibernate配置为依赖Flyway,以便Flyway有机会在Hibernate尝试使用数据库之前初始化数据库。
如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor子类作为设置必要依赖项的便捷方法。例如,如果将Hibernate Search与Elasticsearch一起用作其索引管理器,则EntityManagerFactory必须将任何bean配置为依赖于该elasticsearchClientbean,如以下示例所示:

  1. /**
  2. * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
  3. * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
  4. */
  5. @Component
  6. static class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
  7. extends EntityManagerFactoryDependsOnPostProcessor {
  8. ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
  9. super("elasticsearchClient");
  10. }
  11. }

9.16。使用两个数据源配置jOOQ

如果需要将jOOQ与多个数据源一起使用,则应该DSLContext为每个数据源创建自己的jOOQ 。有关更多详细信息,请参阅JooqAutoConfiguration

特别是,JooqExceptionTranslator并且SpringTransactionProvider可以重复使用,以提供与单个自动配置相似的功能DataSource

10.数据库初始化

可以使用不同的方式初始化SQL数据库,具体取决于堆栈是什么。当然,如果数据库是一个单独的过程,您也可以手动执行。建议使用单一机制进行模式生成。

10.1。使用JPA初始化数据库

JPA具有用于DDL生成的功能,可以将其设置为在启动时针对数据库运行。这是通过两个外部属性控制的:

  • spring.jpa.generate-ddl (布尔值)打开和关闭该功能,并且与供应商无关。
  • spring.jpa.hibernate.ddl-auto(枚举)是一种Hibernate功能,可以更精细地控制行为。此功能将在本指南的后面部分详细介绍。

    10.2。使用Hibernate初始化数据库

    您可以设置spring.jpa.hibernate.ddl-auto明确和标准的Hibernate属性值nonevalidateupdatecreate,和create-drop。Spring Boot根据是否认为您的数据库已嵌入为您选择默认值。默认为create-drop是否未检测到任何模式管理器或none在所有其他情况下。通过查看Connection类型和JDBC URL,可以检测到嵌入式数据库。 hsqldbh2derby是候选人,其他人则不是。从内存数据库切换到“真实”数据库时,请不要对新平台中表和数据的存在做出假设。您必须ddl-auto显式设置或使用其他机制之一来初始化数据库。
您可以通过启用org.hibernate.SQL记录器来输出架构创建。如果启用调试模式,此操作将自动为您完成。

另外,import.sql如果Hibernate从头开始创建模式(即,如果ddl-auto属性设置为createcreate-drop),则在启动时将执行在类路径的根目录中命名的文件。如果您小心的话,这对于演示和测试很有用,但可能不希望出现在生产环境的类路径中。这是Hibernate的功能(与Spring无关)。

10.3。使用基本SQL脚本初始化数据库

Spring Boot可以自动创建您的架构(DDL脚本)DataSource并对其进行初始化(DML脚本)。它分别从标准根类路径位置schema.sql和加载SQL data.sql。另外,Spring Boot处理schema-${platform}.sqldata-${platform}.sql文件(如果存在),其中platform的值为spring.datasource.platform。这使您可以在必要时切换到特定于数据库的脚本。例如,您可以选择将其设置为数据库中的供应商名称(hsqldbh2oraclemysqlpostgresql,等)。

当仅使用基本的SQL脚本时,Spring Boot会自动创建Embedded的架构DataSource。可以使用该spring.datasource.initialization-mode属性来自定义此行为。例如,如果您要始终初始化,则DataSource无论其类型如何:spring.datasource.initialization-mode =总是在基于JPA的应用程序中,您可以选择让Hibernate创建架构或使用schema.sql,但您不能两者都做。spring.jpa.hibernate.ddl-auto如果使用,请确保禁用schema.sql。spring.jpa.hibernate.ddl-auto =无如果使用的是Flyway或Liquibase等高级数据库迁移工具,则应单独使用它们来创建和初始化架构。不建议与Flyway或Liquibase一起使用基本脚本schema.sqldata.sql脚本,并且在以后的版本中将删除支持。

默认情况下,Spring Boot启用Spring JDBC初始化程序的快速失败功能。这意味着,如果脚本导致异常,则应用程序将无法启动。您可以通过设置来调整行为spring.datasource.continue-on-error

10.4。使用R2DBC初始化数据库

如果您使用的是R2DBC,则常规DataSource自动配置会后退,因此不能使用上述任何选项。
您可以在启动时使用SQL脚本初始化数据库,如以下示例所示:

  1. @Configuration(proxyBeanMethods = false)
  2. static class DatabaseInitializationConfiguration {
  3. @Autowired
  4. void initializeDatabase(ConnectionFactory connectionFactory) {
  5. ResourceLoader resourceLoader = new DefaultResourceLoader();
  6. Resource[] scripts = new Resource[] { resourceLoader.getResource("classpath:schema.sql"),
  7. resourceLoader.getResource("classpath:data.sql") };
  8. new ResourceDatabasePopulator(scripts).populate(connectionFactory).block();
  9. }
  10. }

另外,您也可以配置迁飞Liquibase配置DataSource为您办理迁移的持续时间。这两个库均提供用于设置的属性urlusername以及password要迁移的数据库的属性。

选择此选项时,org.springframework:spring-jdbc仍然是必需的依赖项。

10.5。初始化一个Spring Batch数据库

如果您使用Spring Batch,则它随大多数流行的数据库平台一起预包装了SQL初始化脚本。Spring Boot可以检测数据库类型并在启动时执行这些脚本。如果您使用嵌入式数据库,则默认情况下会发生这种情况。您还可以为任何数据库类型启用它,如以下示例所示:
特性
Yaml

  1. spring:
  2. batch:
  3. initialize-schema: "always"

您还可以通过设置spring.batch.initialize-schema为显式关闭初始化never

10.6。使用更高级别的数据库迁移工具

春天引导支持两种更高级别的迁移工具:迁飞Liquibase

10.6.1。在启动时执行Flyway数据库迁移

要在启动时自动运行Flyway数据库迁移,请将添加org.flywaydb:flyway-core到您的类路径中。
通常,迁移是采用以下形式的脚本V<VERSION>__<NAME>.sql(带有<VERSION>下划线分隔的版本,例如“ 1”或“ 2_1”)。默认情况下,它们位于名为的目录中classpath:db/migration,但是您可以通过设置修改该位置spring.flyway.locations。这是一个或多个classpath:或多个filesystem:位置的逗号分隔列表。例如,以下配置将在默认类路径位置和/opt/migration目录中搜索脚本:
特性
Yaml

  1. spring:
  2. flyway:
  3. locations: "classpath:db/migration,filesystem:/opt/migration"

您也可以添加特殊的{vendor}占位符以使用特定于供应商的脚本。假设以下内容:
特性
Yaml

  1. spring:
  2. flyway:
  3. locations: "classpath:db/migration/{vendor}"

db/migration前面的配置不是使用,而是根据数据库的类型(例如,db/migration/mysql对于MySQL)设置要使用的目录。支持的数据库列表在中提供DatabaseDriver
迁移也可以用Java编写。Flyway将使用任何实现的bean自动配置JavaMigration
FlywayProperties提供Flyway的大多数设置以及少量的其他属性,这些属性可用于禁用迁移或关闭位置检查。如果需要对配置进行更多控制,请考虑注册FlywayConfigurationCustomizerBean。
Spring Boot调用Flyway.migrate()以执行数据库迁移。如果您想要更多控制,请提供@Bean实现FlywayMigrationStrategy
Flyway支持SQL和Java回调。要使用基于SQL的回调,请将回调脚本放置在classpath:db/migration目录中。要使用基于Java的回调,请创建一个或多个实现的bean Callback。任何此类bean都会自动向进行注册Flyway。可以通过使用@Order或实现来订购它们OrderedFlywayCallback也可以检测到实现了不推荐使用的接口的Bean ,但是不能与CallbackBean一起使用。
默认情况下,Flyway自动在您的上下文中自动连接(@PrimaryDataSource并将其用于迁移。如果您想使用其他名称DataSource,则可以创建一个并将其标记@Bean@FlywayDataSource。如果这样做并想要两个数据源,请记住创建另一个数据源并将其标记为@Primary。另外,您可以DataSource通过设置spring.flyway.[url,user,password]外部属性来使用Flyway的本机。设置spring.flyway.urlspring.flyway.user足以使Flyway使用其自己的DataSource。如果未设置这三个属性中的任何一个,spring.datasource则将使用其等效属性的值。
您还可以使用Flyway为特定情况提供数据。例如,您可以放入特定于测试的迁移,src/test/resources并且仅在您的应用程序开始进行测试时才运行它们。此外,您可以使用特定于配置文件的配置进行自定义,spring.flyway.locations以便仅在特定配置文件处于活动状态时才运行某些迁移。例如,在中application-dev.properties,您可以指定以下设置:
特性
Yaml

  1. spring:
  2. flyway:
  3. locations: "classpath:/db/migration,classpath:/dev/db/migration"

使用该设置,dev/db/migration仅在dev配置文件处于活动状态时才运行迁移。

10.6.2。在启动时执行Liquibase数据库迁移

要在启动时自动运行Liquibase数据库迁移,请将添加org.liquibase:liquibase-core到您的类路径中。

当您将+添加org.liquibase:liquibase-core到类路径时,默认情况下,数据库迁移将在应用程序启动期间以及测试运行之前运行。可以通过使用spring.liquibase.enabled属性来自定义行为,并在maintest配置中设置不同的值。不可能使用两种不同的方式来初始化数据库(例如,Liquibase用于应用程序启动,JPA用于测试运行)。

默认情况下,从中读取主更改日志db/changelog/db.changelog-master.yaml,但是您可以通过设置来更改位置spring.liquibase.change-log。除了YAML,Liquibase还支持JSON,XML和SQL更改日志格式。
默认情况下,Liquibase自动在您的上下文中自动连接(@PrimaryDataSource并将其用于迁移。如果需要使用其他名称DataSource,则可以创建一个并将其标记@Bean@LiquibaseDataSource。如果这样做,并且想要两个数据源,请记住创建另一个数据源并将其标记为@Primary。另外,您可以DataSource通过设置spring.liquibase.[driver-class-name,url,user,password]外部属性来使用Liquibase的本机。设置spring.liquibase.urlspring.liquibase.user足以使Liquibase使用其自己的DataSource。如果未设置这三个属性中的任何一个,spring.datasource则将使用其等效属性的值。
请参阅LiquibaseProperties以获取有关可用设置的详细信息,例如上下文,默认架构和其他。

11.消息传递

Spring Boot提供了许多包含消息传递的启动器。本部分回答了将消息与Spring Boot一起使用所引起的问题。

11.1。禁用事务JMS会话

如果您的JMS代理不支持事务处理会话,则必须完全禁用对事务的支持。如果您创建自己的JmsListenerContainerFactory,则无所事事,因为默认情况下无法进行交易。如果您想使用DefaultJmsListenerContainerFactoryConfigurer来重用Spring Boot的默认设置,则可以禁用事务性会话,如下所示:

  1. @Bean
  2. public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
  3. ConnectionFactory connectionFactory,
  4. DefaultJmsListenerContainerFactoryConfigurer configurer) {
  5. DefaultJmsListenerContainerFactory listenerFactory =
  6. new DefaultJmsListenerContainerFactory();
  7. configurer.configure(listenerFactory, connectionFactory);
  8. listenerFactory.setTransactionManager(null);
  9. listenerFactory.setSessionTransacted(false);
  10. return listenerFactory;
  11. }

前面的示例将覆盖默认工厂,并且应将其应用于应用程序定义的任何其他工厂(如果有)。

12.批处理应用

当人们从Spring Boot应用程序中使用Spring Batch时,经常会出现许多问题。本节解决这些问题。

12.1。指定批处理数据源

默认情况下,批处理应用程序需要一个DataSource来存储作业详细信息。Spring BatchDataSource默认情况下需要一个。要使用它而DataSource不是应用程序的main DataSource,声明一个DataSourcebean,并用注释其@Bean方法@BatchDataSource。如果这样做并需要两个数据源,请记住标记另一个@Primary。要获得更大的控制权,请实施BatchConfigurer。有关更多详细信息,请参见Javadoc@EnableBatchProcessing
有关Spring Batch的更多信息,请参见Spring Batch项目页面

12.2。在启动时运行Spring Batch作业

通过添加@EnableBatchProcessing到您的@Configuration类之一来启用Spring Batch自动配置。
默认情况下,它在启动时在应用程序上下文中执行所有操作 JobsJobLauncherApplicationRunner有关详细信息,请参见)。您可以通过指定spring.batch.job.names(使用逗号分隔的作业名称模式列表)缩小到一个或多个特定作业。
有关更多详细信息,请参见BatchAutoConfiguration@EnableBatchProcessing

12.3。从命令行运行

Spring Boot将以开头的任何命令行参数转换--为要添加到的属性Environment,请参见访问命令行属性。这不应用于将参数传递给批处理作业。要在命令行上指定批处理参数,请使用常规格式(即,不带--),如以下示例所示:
$ java -jar myapp.jar someParameter = someValue anotherParameter = anotherValue
如果Environment在命令行上指定的属性,则作业将忽略它。考虑以下命令:
$ java -jar myapp.jar —server.port = 7070 someParameter = someValue
这仅向批处理作业提供一个参数:someParameter=someValue

12.4。存储作业库

Spring Batch需要用于Job存储库的数据存储。如果使用Spring Boot,则必须使用实际的数据库。请注意,它可以是内存数据库,请参阅“配置作业存储库”

13.执行器

Spring Boot包括Spring Boot执行器。本节回答了经常因使用而引起的问题。

13.1。更改执行器端点的HTTP端口或地址

在独立应用程序中,Actuator HTTP端口默认与主HTTP端口相同。要使应用程序在其他端口上侦听,请设置外部属性:management.server.port。要侦听完全不同的网络地址(例如,当您有一个用于管理的内部网络而有一个用于用户应用程序的外部网络)时,还可以设置management.server.address为服务器可以绑定到的有效IP地址。
有关更多详细信息,请参见ManagementServerProperties源代码和“生产就绪功能”部分中的“ production-ready-features.html”。

13.2。自定义“ whitelabel”错误页面

如果遇到服务器错误,Spring Boot会安装一个“ whitelabel”错误页面,您会在浏览器客户端中看到该错误页面(使用JSON和其他媒体类型的机器客户端应该看到带有正确错误代码的明智响应)。

设置server.error.whitelabel.enabled=false以关闭默认错误页面。这样做将还原您正在使用的servlet容器的默认值。请注意,Spring Boot仍然尝试解决错误视图,因此您应该添加自己的错误页面,而不是完全禁用它。

用自己的方法覆盖错误页面取决于您使用的模板技术。例如,如果您使用Thymeleaf,则可以添加error.html模板。如果您使用FreeMarker,则可以添加error.ftlh模板。通常,您需要View使用名称解析的error@Controller处理/error路径的。除非你更换了一些默认配置,你应该找一个BeanNameViewResolverApplicationContext,所以@Bean命名error是这样做的一种方式。请参阅ErrorMvcAutoConfiguration以获取更多选项。
有关如何在Servlet容器中注册处理程序的详细信息,另请参见“错误处理”部分。

13.3。消毒敏感值

envconfigprops端点返回的信息可能有些敏感,因此默认情况下会清理与某个模式匹配的键(即,它们的值将替换为******)。
可以分别使用management.endpoint.env.keys-to-sanitize和来定制要使用的模式management.endpoint.configprops.keys-to-sanitize
Spring Boot对此类密钥使用明智的默认设置:以单词“ password”,“ secret”,“ key”,“ token”,“ vcap_services”,“ sun.java.command”结尾的任何密钥都已完全清除。此外,将包含单词credentials作为键的一部分的任何键都进行清理(配置为正则表达式,即*credentials.*)。
此外,Spring Boot只对以“ uri”,“ uris”,“ address”或“ addresss”结尾的密钥的URI敏感部分进行清理。URI的敏感部分使用格式标识<scheme>://<username>:<password>@<host>:<port>/。例如,对于该属性myclient.uri=http://user1:password1@localhost:8081,最终的净化值是 http://user1:******@localhost:8081

13.4。将健康指标映射到千分尺

Spring Boot运行状况指示器返回一个Status类型,以指示整个系统的运行状况。如果要监视或警告特定应用程序的运行状况,则可以通过千分尺将这些状态导出为度量。默认情况下,Spring Boot使用状态代码“ UP”,“ DOWN”,“ OUT_OF_SERVICE”和“ UNKNOWN”。要导出这些状态,您需要将这些状态转换为一组数字,以便它们可以与Micrometer一起使用Gauge
以下示例显示了编写此类导出程序的一种方法:

  1. @Configuration
  2. public class HealthMetricsConfiguration {
  3. public HealthMetricsConfiguration(MeterRegistry registry, HealthEndpoint healthEndpoint) {
  4. // This example presumes common tags (such as the app) are applied elsewhere
  5. Gauge.builder("health", healthEndpoint, this::getStatusCode).strongReference(true).register(registry);
  6. }
  7. private int getStatusCode(HealthEndpoint health) {
  8. Status status = health.health().getStatus();
  9. if (Status.UP.equals(status)) {
  10. return 3;
  11. }
  12. if (Status.OUT_OF_SERVICE.equals(status)) {
  13. return 2;
  14. }
  15. if (Status.DOWN.equals(status)) {
  16. return 1;
  17. }
  18. return 0;
  19. }
  20. }

14.安全性

本部分解决有关使用Spring Boot时的安全性的问题,包括因将Spring Security与Spring Boot一起使用而引起的问题。
有关Spring Security的更多信息,请参见Spring Security项目页面

14.1。关闭Spring Boot安全性配置

如果在应用程序中@Configuration使用WebSecurityConfigurerAdapterSecurityFilterChainBean定义a ,它将关闭Spring Boot中的默认webapp安全设置。

14.2。更改UserDetailsService并添加用户帐户

如果你提供了一个@Bean类型的AuthenticationManagerAuthenticationProvider或者UserDetailsService,默认@BeanInMemoryUserDetailsManager不创建。这意味着您拥有完整的Spring Security功能集(例如各种身份验证选项)。
添加用户帐户的最简单方法是提供您自己的UserDetailsServicebean。

14.3。在代理服务器上运行时启用HTTPS

确保所有主要端点仅可通过HTTPS进行访问对于任何应用程序来说都是一项重要的工作。如果您将Tomcat用作servlet容器,则Spring BootRemoteIpValve如果检测到某些环境设置,则会自动添加Tomcat自己的Tomcat ,并且您应该能够依靠TomcatHttpServletRequest报告其是否安全(甚至在处理代理服务器的下游)。真正的SSL终止)。标准行为由某些请求标头(x-forwarded-forx-forwarded-proto)的存在或不存在决定,它们的名称是常规名称,因此它应适用于大多数前端代理。您可以通过向中添加一些条目来打开阀门application.properties,如以下示例所示:
特性
Yaml

  1. server:
  2. tomcat:
  3. remoteip:
  4. remote-ip-header: "x-forwarded-for"
  5. protocol-header: "x-forwarded-proto"

(这些属性中的任何一个都会在阀上切换。或者,您可以RemoteIpValve通过TomcatServletWebServerFactory使用WebServerFactoryCustomizerbean来定制来添加。)
要将Spring Security配置为要求所有(或某些)请求使用安全通道,请考虑添加自己的SecurityFilterChainbean,该bean添加以下HttpSecurity配置:

  1. @Bean
  2. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  3. // Customize the application security
  4. http.requiresChannel().anyRequest().requiresSecure();
  5. return http.build();
  6. }

15.热交换

Spring Boot支持热插拔。本部分回答有关其工作方式的问题。

15.1。重新加载静态内容

有几种热重装选项。推荐的方法是使用spring-boot-devtools,因为它提供了其他开发时功能,例如对快速应用程序重新启动和LiveReload的支持,以及合理的开发时配置(例如模板缓存)。Devtools通过监视类路径的更改来工作。这意味着必须“构建”静态资源更改才能使更改生效。默认情况下,当您保存更改时,这会自动在Eclipse中发生。在IntelliJ IDEA中,“生成项目”命令将触发必要的构建。由于默认的重新启动排除项,对静态资源的更改不会触发应用程序的重新启动。但是,它们确实会触发实时重新加载。
另外,在IDE中运行(特别是在调试时运行)是进行开发的好方法(所有现代IDE都允许重新加载静态资源,并且通常还允许热交换Java类更改)。
最后,可以配置Maven和Gradle插件(请参阅addResources属性)以支持从命令行运行,并直接从源中重新加载静态文件。如果要使用高级工具编写该代码,则可以将其与外部css / js编译器进程一起使用。

15.2。重新加载模板而无需重新启动容器

Spring Boot支持的大多数模板技术都包含用于禁用缓存的配置选项(在本文档的后面介绍)。如果使用spring-boot-devtools模块,则在开发时会自动为您配置这些属性。

15.2.1。胸腺模板

如果您使用Thymeleaf,请将设置spring.thymeleaf.cachefalse。有关ThymeleafAutoConfiguration其他Thymeleaf定制选项,请参见。

15.2.2。FreeMarker模板

如果使用FreeMarker,请设置spring.freemarker.cachefalse。有关FreeMarkerAutoConfiguration其他FreeMarker定制选项,请参见。

15.2.3。Groovy模板

如果您使用Groovy模板,请设置spring.groovy.template.cachefalse。请参阅参考资料,GroovyTemplateAutoConfiguration以获取其他Groovy定制选项。

15.3。快速应用重启

spring-boot-devtools模块包括对应用程序自动重启的支持。尽管不如JRebel这样的技术快,但通常比“冷启动”要快得多。在研究本文档后面讨论的一些更复杂的重载选项之前,您可能应该先尝试一下。
有关更多详细信息,请参见using-spring-boot.html部分。

15.4。在不重新启动容器的情况下重新加载Java类

许多现代的IDE(Eclipse,IDEA等)都支持字节码的热交换。因此,如果所做的更改不影响类或方法的签名,则应干净地重新加载而没有副作用。

16.建造

Spring Boot包括Maven和Gradle的构建插件。本部分回答有关这些插件的常见问题。

16.1。生成构建信息

Maven插件和Gradle插件都允许生成包含项目的坐标,名称和版本的构建信息。还可以将插件配置为通过配置添加其他属性。当存在这样的文件时,Spring Boot会自动配置一个BuildPropertiesbean。
要使用Maven生成构建信息,请为build-info目标添加执行,如以下示例所示:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <version>2.4.3</version>
  7. <executions>
  8. <execution>
  9. <goals>
  10. <goal>build-info</goal>
  11. </goals>
  12. </execution>
  13. </executions>
  14. </plugin>
  15. </plugins>
  16. </build>
有关更多详细信息,请参见Spring Boot Maven插件文档

下面的示例对Gradle执行相同的操作:

  1. springBoot {
  2. buildInfo()
  3. }
有关更多详细信息,请参见Spring Boot Gradle插件文档

16.2。生成Git信息

Maven和Gradle都允许生成一个git.properties文件,其中包含有关git构建项目时源代码存储库状态的信息。
对于Maven用户,spring-boot-starter-parentPOM包含一个预配置的插件来生成git.properties文件。要使用它,请将以下声明添加到您的POM中:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>pl.project13.maven</groupId>
  5. <artifactId>git-commit-id-plugin</artifactId>
  6. </plugin>
  7. </plugins>
  8. </build>

Gradle用户可以通过使用gradle-git-properties插件获得相同的结果,如以下示例所示:

  1. plugins {
  2. id "com.gorylenko.gradle-git-properties" version "2.2.4"
  3. }

Maven和Gradle插件都允许git.properties配置其中包含的属性。

提交时间git.properties应与以下格式匹配:yyyy-MM-dd’T’HH:mm:ssZ。这是上面列出的两个插件的默认格式。使用此格式,可以将时间解析为,Date并将其序列化为JSON时的格式由Jackson的日期序列化配置设置控制。

16.3。自定义依赖版本

spring-boot-dependenciesPOM管理公共依赖的版本。Maven和Gradle的Spring Boot插件允许使用构建属性来自定义这些托管依赖项版本。

每个Spring Boot发行版均针对这组特定的第三方依赖项进行了设计和测试。覆盖版本可能会导致兼容性问题。

要使用Maven覆盖依赖版本,请参阅Maven插件文档的这一部分
要覆盖Gradle中的依赖版本,请参阅Gradle插件文档的这一部分

16.4。使用Maven创建可执行JAR

spring-boot-maven-plugin可用于创建可执行的“肥肉” JAR。如果使用spring-boot-starter-parentPOM,则可以声明插件,然后将jar重新包装如下:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. </plugin>
  7. </plugins>
  8. </build>

如果您不使用父POM,则仍然可以使用该插件。但是,您必须另外添加一个<executions>部分,如下所示:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <version>2.4.3</version>
  7. <executions>
  8. <execution>
  9. <goals>
  10. <goal>repackage</goal>
  11. </goals>
  12. </execution>
  13. </executions>
  14. </plugin>
  15. </plugins>
  16. </build>

有关完整用法的详细信息,请参见插件文档

16.5。使用Spring Boot应用程序作为依赖项

像war文件一样,Spring Boot应用程序也不打算用作依赖项。如果您的应用程序包含要与其他项目共享的类,建议的方法是将该代码移到单独的模块中。然后,您的应用程序和其他项目可以依赖单独的模块。
如果您不能按照上面的建议重新排列代码,则必须配置Spring Boot的Maven和Gradle插件以生成一个单独的工件,该工件适合用作依赖项。可执行档案不能用作依赖项,因为可执行jar格式将打包应用程序类BOOT-INF/classes。这意味着当将可执行jar用作依赖项时,找不到它们。
为了产生两个工件,一个可以用作依赖项,另一个可以执行,必须指定分类器。该分类器应用于可执行档案的名称,保留默认档案作为依赖项。
exec在Maven中配置分类器,可以使用以下配置:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <configuration>
  7. <classifier>exec</classifier>
  8. </configuration>
  9. </plugin>
  10. </plugins>
  11. </build>

16.6。运行可执行jar时提取特定的库

可执行jar中的大多数嵌套库无需解压缩即可运行。但是,某些库可能会有问题。例如,JRuby包含其自己的嵌套jar支持,它假定jruby-complete.jar总是可以直接以文件的形式直接使用。
要处理任何有问题的库,您可以标记在可执行jar首次运行时应自动解压缩特定的嵌套jar。这些嵌套的jar会写在java.io.tmpdirsystem属性标识的临时目录下。

应注意确保已配置您的操作系统,以使其在应用程序仍在运行时不会删除已解压缩到临时目录中的jar。

例如,为了指示应该使用Maven插件将JRuby标记为解包,您可以添加以下配置:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <configuration>
  7. <requiresUnpack>
  8. <dependency>
  9. <groupId>org.jruby</groupId>
  10. <artifactId>jruby-complete</artifactId>
  11. </dependency>
  12. </requiresUnpack>
  13. </configuration>
  14. </plugin>
  15. </plugins>
  16. </build>

16.7。创建带有排除项的不可执行的JAR

通常,如果您具有一个可执行文件和一个不可执行的jar作为两个单独的构建产品,则可执行版本具有库jar中不需要的其他配置文件。例如,application.yml配置文件可能会从不可执行的JAR中排除。
在Maven中,可执行jar必须是主要工件,您可以为库添加一个分类的jar,如下所示:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. </plugin>
  7. <plugin>
  8. <artifactId>maven-jar-plugin</artifactId>
  9. <executions>
  10. <execution>
  11. <id>lib</id>
  12. <phase>package</phase>
  13. <goals>
  14. <goal>jar</goal>
  15. </goals>
  16. <configuration>
  17. <classifier>lib</classifier>
  18. <excludes>
  19. <exclude>application.yml</exclude>
  20. </excludes>
  21. </configuration>
  22. </execution>
  23. </executions>
  24. </plugin>
  25. </plugins>
  26. </build>

16.8。远程调试以Maven开头的Spring Boot应用程序

要将远程调试器附加到使用Maven启动的Spring Boot应用程序,可以使用maven pluginjvmArguments属性。
有关更多详细信息,请参见此示例

16.9。不使用spring-boot-antlib从Ant构建可执行存档

要使用Ant进行构建,您需要获取依赖项,进行编译,然后创建一个jar或war存档。要使其可执行,可以使用该spring-boot-antlib模块,也可以按照以下说明进行操作:

  1. 如果要构建jar,请将应用程序的类和资源打包在嵌套BOOT-INF/classes目录中。如果要发动战争,请WEB-INF/classes照常将应用程序的类打包在嵌套目录中。
  2. BOOT-INF/libjar或WEB-INF/libwar的嵌套目录中添加运行时依赖项。切记不要压缩存档中的条目。
  3. provided(嵌入式容器)依赖项添加到BOOT-INF/libjar或WEB-INF/lib-providedwar的嵌套目录中。切记不要压缩存档中的条目。
  4. spring-boot-loader类添加到存档的根目录(以便Main-Class可用)。
  5. 使用适当的启动器(例如JarLauncherjar文件)作为Main-Class清单中的属性,并指定其所需的其他属性作为清单条目(主要是通过设置Start-Class属性)。

以下示例显示了如何使用Ant构建可执行归档文件:

  1. <target name="build" depends="compile">
  2. <jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
  3. <mappedresources>
  4. <fileset dir="target/classes" />
  5. <globmapper from="*" to="BOOT-INF/classes/*"/>
  6. </mappedresources>
  7. <mappedresources>
  8. <fileset dir="src/main/resources" erroronmissingdir="false"/>
  9. <globmapper from="*" to="BOOT-INF/classes/*"/>
  10. </mappedresources>
  11. <mappedresources>
  12. <fileset dir="${lib.dir}/runtime" />
  13. <globmapper from="*" to="BOOT-INF/lib/*"/>
  14. </mappedresources>
  15. <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
  16. <manifest>
  17. <attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
  18. <attribute name="Start-Class" value="${start-class}" />
  19. </manifest>
  20. </jar>
  21. </target>

17.传统部署

Spring Boot支持传统部署以及更现代的部署形式。本节回答有关传统部署的常见问题。

17.1。创建可部署的战争文件

由于Spring WebFlux不严格依赖Servlet API,并且默认情况下将应用程序部署在嵌入式Reactor Netty服务器上,因此WebFlux应用程序不支持War部署。

产生可部署war文件的第一步是提供一个SpringBootServletInitializer子类并覆盖其configure方法。这样做利用了Spring Framework的Servlet 3.0支持,并允许您在由Servlet容器启动应用程序时对其进行配置。通常,应将应用程序的主类更新为extend SpringBootServletInitializer,如以下示例所示:

  1. @SpringBootApplication
  2. public class Application extends SpringBootServletInitializer {
  3. @Override
  4. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  5. return application.sources(Application.class);
  6. }
  7. public static void main(String[] args) {
  8. SpringApplication.run(Application.class, args);
  9. }
  10. }

下一步是更新构建配置,以便您的项目生成war文件而不是jar文件。如果您使用Maven和spring-boot-starter-parent(为您配置Maven的war插件),那么您要做的就是修改pom.xml以将包装更改为war,如下所示:

  1. <packaging>war</packaging>

如果使用Gradle,则需要进行修改,build.gradle以将war插件应用于项目,如下所示:

  1. apply plugin: 'war'

该过程的最后一步是确保嵌入式servlet容器不干扰war文件所部署到的servlet容器。为此,您需要将嵌入式Servlet容器依赖性标记为已提供。
如果使用Maven,则以下示例将servlet容器(在本例中为Tomcat)标记为已提供:

  1. <dependencies>
  2. <!-- … -->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-tomcat</artifactId>
  6. <scope>provided</scope>
  7. </dependency>
  8. <!-- … -->
  9. </dependencies>

如果使用Gradle,则以下示例将servlet容器(在本例中为Tomcat)标记为已提供:

  1. dependencies {
  2. // …
  3. providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
  4. // …
  5. }
providedRuntime比Gradle的compileOnly配置更可取。除其他限制外,compileOnly依赖项不在测试类路径上,因此任何基于Web的集成测试都将失败。

如果您使用Spring Boot构建工具,则将提供的嵌入式servlet容器依赖关系标记为提供,将生成可执行的war文件,并将提供的依赖关系打包在lib-provided目录中。这意味着,除了可以部署到servlet容器之外,还可以通过java -jar在命令行上使用运行应用程序。

17.2。将现有应用程序转换为Spring Boot

要将现有的非Web Spring应用程序转换为Spring Boot应用程序,请替换创建您的代码ApplicationContext并将其替换为SpringApplication或的调用SpringApplicationBuilder。Spring MVC Web应用程序通常适合首先创建可部署的war应用程序,然后再将其迁移到可执行的war或jar。请参阅有关将罐子转换为战争的入门指南
要通过扩展SpringBootServletInitializer(例如,在名为的类中Application)并添加Spring Boot@SpringBootApplication注释来创建可部署的战争,请使用类似于以下示例中所示的代码:

  1. @SpringBootApplication
  2. public class Application extends SpringBootServletInitializer {
  3. @Override
  4. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  5. // Customize the application or call application.sources(...) to add sources
  6. // Since our example is itself a @Configuration class (via @SpringBootApplication)
  7. // we actually don't need to override this method.
  8. return application;
  9. }
  10. }

请记住,无论您放置什么,sources都仅是Spring ApplicationContext。通常,任何已经起作用的东西都应该在这里工作。也许有些bean可以稍后删除,然后让Spring Boot为它们提供自己的默认值,但是应该可以使某些东西工作,然后再执行此操作。
可以将静态资源移至类路径根目录中/public(或/static/resources/META-INF/resources)。这同样适用于messages.properties(Spring Boot自动在类路径的根目录中检测到)。
SpringDispatcherServlet和Spring Security的香草用法应该不需要进一步更改。如果您的应用程序具有其他功能(例如,使用其他servlet或过滤器),则可能需要Application通过从中替换这些元素来为上下文添加一些配置web.xml,如下所示:

  • @Bean类型的ServletServletRegistrationBean将安装豆在容器中,好像它是一个<servlet/><servlet-mapping/>web.xml
  • @Bean型的FilterFilterRegistrationBean表现得类似(作为<filter/><filter-mapping/>)。
  • 一个ApplicationContextXML文件可以通过添加@ImportResource在你的Application。或者,可以在几行中重新创建已经大量使用注释配置的情况作为@Bean定义。

war文件运行后,可以通过向中添加main方法来使其可执行Application,如以下示例所示:

  1. public static void main(String[] args) {
  2. SpringApplication.run(Application.class, args);
  3. }

| | 如果打算以战争或可执行应用程序的形式启动应用程序,则需要使用对SpringBootServletInitializer回调函数可用的方法和main类似于以下类的方法共享构建器的自定义项:``` @SpringBootApplication public class Application extends SpringBootServletInitializer {

  1. **@Override**
  2. **protected** SpringApplicationBuilder **configure**(SpringApplicationBuilder builder) {
  3. **return** configureApplication(builder);
  4. }
  5. **public** **static** **void** **main**(String[] args) {
  6. configureApplication(**new** SpringApplicationBuilder()).run(args);
  7. }
  8. **private** **static** SpringApplicationBuilder **configureApplication**(SpringApplicationBuilder builder) {
  9. **return** builder.sources(Application.class).bannerMode(Banner.Mode.OFF);
  10. }

}

  1. |
  2. | :---: | --- |
  3. 应用程序可以分为多个类别:
  4. - 没有的Servlet 3.0+应用程序`web.xml`。<br />
  5. - 带有的应用程序`web.xml`。<br />
  6. - 具有上下文层次结构的应用程序。<br />
  7. - 没有上下文层次结构的应用程序。<br />
  8. 所有这些都应该适合翻译,但每种都可能需要稍微不同的技术。<br />如果Servlet 3.0+应用程序已经使用了Spring Servlet 3.0+初始化程序支持类,那么它们可能会很容易转换。通常,来自现有代码的所有代码`WebApplicationInitializer`都可以移入`SpringBootServletInitializer`。如果您现有的应用程序有多个`ApplicationContext`(例如,如果使用`AbstractDispatcherServletInitializer`),则可以将所有上下文源组合为一个`SpringApplication`。您可能遇到的主要并发症是,如果合并不起作用,并且您需要维护上下文层次结构。有关示例,请参见[有关构建层次结构](https://docs.spring.io/spring-boot/docs/2.4.3/reference/html/howto.html#howto-build-an-application-context-hierarchy)的[条目](https://docs.spring.io/spring-boot/docs/2.4.3/reference/html/howto.html#howto-build-an-application-context-hierarchy)。通常需要分解包含特定于Web的功能的现有父上下文,以便所有`ServletContextAware`组件都在子上下文中。<br />还不是Spring应用程序的应用程序可以转换为Spring Boot应用程序,前面提到的指南可能会有所帮助。但是,您可能仍然遇到问题。在这种情况下,建议您[使用标记来在Stack Overflow上提问`spring-boot`](https://stackoverflow.com/questions/tagged/spring-boot)。
  9. <a name="howto-weblogic"></a>
  10. ### 17.3。将WAR部署到WebLogic
  11. 要将Spring Boot应用程序部署到WebLogic,必须确保servlet初始化程序**直接**实现`WebApplicationInitializer`(即使您从已经实现了它的基类进行扩展)。<br />WebLogic的典型初始化程序应类似于以下示例:

import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.web.WebApplicationInitializer; @SpringBootApplication public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer { }

  1. 如果使用Logback,则还需要告诉WebLogic首选打包版本,而不是服务器预先安装的版本。您可以通过添加`WEB-INF/weblogic.xml`具有以下内容的文件来做到这一点:

<?xml version=”1.0” encoding=”UTF-8”?>

org.slf4j

  1. <a name="howto-use-jedis-instead-of-lettuce"></a>
  2. ### 17.4。使用Jedis代替生菜
  3. 默认情况下,Spring Boot入门(`spring-boot-starter-data-redis`)使用[Lettuce](https://github.com/lettuce-io/lettuce-core/)。您需要排除该依赖性,而改为包含[Jedis](https://github.com/xetorthio/jedis/)。Spring Boot管理这两个依赖关系,因此您无需指定版本即可切换到Jedis。<br />以下示例显示了如何在Maven中执行此操作:

org.springframework.boot spring-boot-starter-data-redis io.lettuce lettuce-core

redis.clients jedis

  1. 以下示例显示了如何在Gradle中执行此操作:

dependencies { implementation(‘org.springframework.boot:spring-boot-starter-data-redis’) { exclude group: ‘io.lettuce’, module: ‘lettuce-core’ } implementation ‘redis.clients:jedis’ // … }

  1. <a name="howto-testcontainers"></a>
  2. ### 17.5。使用Testcontainer进行集成测试
  3. 该[Testcontainers](https://www.testcontainers.org/)库提供了一种方法来管理Docker容器中运行的服务。它与JUnit集成,允许您编写一个测试类,该类可以在运行任何测试之前启动容器。Testcontainers在编写与真实的后端服务(例如MySQL,MongoDB,Cassandra等)进行通信的集成测试时特别有用。Testcontainers可以在Spring Boot测试中使用,如下所示:

@SpringBootTest @Testcontainers class ExampleIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>(); }

  1. 在运行任何测试之前,这将启动运行Neo4jDocker容器(如果Docker在本地运行)。在大多数情况下,您将需要使用正在运行的容器中的详细信息(例如容器IP或端口)来配置应用程序。<br />这可以通过`@DynamicPropertySource`允许将动态属性值添加到Spring Environment的静态方法来完成。

@SpringBootTest @Testcontainers class ExampleIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>(); @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add(“spring.neo4j.uri”, neo4j::getBoltUrl); } } ``` 上面的配置允许应用程序中与Neo4j相关的Bean与在Testcontainers管理的Docker容器中运行的Neo4j通信。