本部分提供了一些常见问题的解答:我该如何做那个…在使用Spring Boot时经常出现的问题。它的报道不是详尽的,但确实涵盖了相当多的内容。
如果您有我们这里没有介绍的特定问题,您可能需要查看stackoverflow.com,看看是否有人已经提供了答案。这也是提出新问题的好地方(请使用SpringBoot
标记)。
我们也非常乐意延长这一部分。如果您想添加How-to,请向我们发送拉取请求。
1. Spring Boot Application
本节包括与Spring Boot应用程序直接相关的主题。
1.1. Create Your Own FailureAnalyzer
FailureAnalyzer
是在启动时拦截异常并将其转换为人类可读的消息的一种很好的方法,该消息包装在中。Spring Boot为与应用程序上下文相关的异常、JSR-303验证等提供了这样的分析器。您也可以创建自己的应用程序。
AbstractFailureAnalyzer
是FailureAnalyzer
的方便扩展,它检查要处理的异常中是否存在指定的异常类型。您可以在此基础上进行扩展,以便您的实现只有在异常实际存在时才有机会处理它。无论出于何种原因,如果您无法处理该异常,则返回NULL
,以便让另一个实现有机会处理该异常。
FailureAnalyzer
实现必须在META-INF/spring.Factory
中注册。以下示例注册ProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.example.ProjectConstraintViolationFailureAnalyzer
If you need access to the BeanFactory or the Environment , your FailureAnalyzer can implement BeanFactoryAware or EnvironmentAware respectively. |
1.2. Troubleshoot Auto-configuration
Spring Boot自动配置会尽最大努力“做正确的事情”,但有时事情会失败,而且很难说出原因。
在任何Spring BootApplicationContext
中都有非常有用的ConditionEvaluationReport
。如果启用调试
记录输出,则可以看到它。如果您使用SpringBoot-Actuator
(请参阅the Actuator章节),那么还有一个Conditions
端点可以在JSON中呈现报表。使用该端点来调试应用程序,并查看Spring Boot在运行时添加了(和没有添加)了哪些功能。
更多问题可以通过查看源代码和Javadoc来回答。阅读代码时,请记住以下经验法则:
-
查找名为
*Autoconfiguration
的类,并阅读它们的源代码。请特别注意@Conditional*
注释,以找出它们启用了哪些功能以及何时启用。将--DEBUG
添加到命令行或系统属性-DDEBUG
,以在控制台上获取在应用程序中做出的所有自动配置决策的日志。在启用了Actuator的运行应用程序中,查看Conditions
端点(/Actuator/Conditions
或JMX等效项)以了解相同的信息。 -
查找
@ConfigurationProperties
的类(例如ServerProperties
),并从中读取可用的外部配置选项。@ConfigurationProperties
批注有一个name
属性,该属性充当外部属性的前缀。因此,ServerProperties
有prefix=“服务器”
,其配置属性是server.port
、server.Address
等。在启用了执行器的运行应用程序中,查看configprops
端点。 -
寻找在
绑定器
上使用Bind
方法,以轻松的方式从Environment
显式拉出配置值。它经常与前缀连用。 -
查找直接绑定到
环境
的@Value
批注。 -
查找响应Spel表达式打开和关闭功能的
@ConditionalOnExpression
注释,通常使用从Environment
解析的占位符进行计算。
1.3. Customize the Environment or ApplicationContext Before It Starts
SpringApplication
具有用于将自定义应用于上下文或环境的ApplicationListeners
和ApplicationContextInitializers
。Spring Boot从META-INF/spring.Factory
加载许多这样的定制供内部使用。注册附加自定义的方式有多种:
-
以编程方式针对每个应用程序,在运行它之前调用
SpringApplication
上的addListeners
和addInitializers
方法。 -
声明性地针对每个应用程序,通过设置
context.Initializer.class
或context.listener.class
属性。 -
声明性地,对于所有应用程序,通过添加
META-INF/spring.Factory
并打包一个JAR文件,应用程序都将其作为库使用。
SpringApplication
将一些特殊的ApplicationEvent
发送给侦听器(有些甚至在创建上下文之前),然后也为ApplicationContext
发布的事件注册侦听器。有关完整列表,请参阅“Spring Boot特性”部分中的“应用程序事件和侦听器”。
还可以在刷新应用程序上下文之前使用Environment PostProcessor
自定义Environment
。每个实现都应该在META-INF/spring.Factory
中注册,如下例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将它们添加到环境
。例如,下面的示例从类路径加载YAML配置文件:
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { Resource path = new ClassPathResource("com/example/myapp/config.yml"); PropertySource<?> propertySource = loadYaml(path); environment.getPropertySources().addLast(propertySource); } private PropertySource<?> loadYaml(Resource path) { Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist"); try { return this.loader.load("custom-resource", path).get(0); } catch (IOException ex) { throw new IllegalStateException("Failed to load yaml configuration from " + path, ex); } } }
The Environment has already been prepared with all the usual property sources that Spring Boot loads by default. It is therefore possible to get the location of the file from the environment. The preceding example adds the custom-resource property source at the end of the list so that a key defined in any of the usual other locations takes precedence. A custom implementation may define another order. |
While using @PropertySource on your @SpringBootApplication may seem to be a convenient way to load a custom resource in the Environment , we do not recommend it. Such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins. |
1.4. Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)
您可以使用ApplicationBuilder
类创建父/子ApplicationContext
层次结构。有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。
1.5. Create a Non-web Application
并非所有的Spring应用程序都必须是Web应用程序(或Web服务)。如果您希望执行main
方法中的一些代码,但还要引导一个Spring应用程序以设置要使用的基础结构,则可以使用Spring Boot的SpringApplication
功能。SpringApplication
根据它是否认为需要Web应用程序来更改其ApplicationContext
类。您可以做的第一件事是将与服务器相关的依赖项(如Servlet API)从类路径中去掉。如果您无法做到这一点(例如,您从相同的代码库运行两个应用程序),那么您可以显式地在SpringApplication
实例上调用setWebApplicationType(WebApplicationType.NONE)
或设置ApplationConextClass
属性(通过Java API或使用外部属性)。您希望作为业务逻辑运行的应用程序代码可以实现为CommandLineRunner
,并作为@Bean
定义放入上下文中。
2. Properties and Configuration
本节包括有关设置和读取属性和配置设置以及它们与Spring Boot应用程序交互的主题。
2.1. Automatically Expand Properties at Build Time
您可以使用现有的生成配置自动展开某些属性,而不是对项目的生成配置中也指定的某些属性进行硬编码。这在Maven和Gradle中都是可能的。
2.1.1. Automatic Property Expansion Using Maven
通过使用资源筛选,您可以自动展开Maven项目中的属性。如果您使用SpringBoot-starter-Parent
,则可以使用@..@
占位符引用您的Maven‘项目属性’,如下例所示:
app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@
Only production configuration is filtered that way (in other words, no filtering is applied on src/test/resources ). |
If you enable the addResources flag, the spring-boot:run goal can add src/main/resources directly to the classpath (for hot reloading purposes). Doing so circumvents the resource filtering and this feature. Instead, you can use the exec:java goal or customize the plugin’s configuration. See the plugin usage page for more details. |
如果不使用起始父级,则需要在pom.xml
的<;Build/>;
元素中包含以下元素:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
您还需要在<;plugins/>;
中包含以下元素:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
The useDefaultDelimiters property is important if you use standard Spring placeholders (such as ${placeholder} ) in your configuration. If that property is not set to false , these may be expanded by the build. |
2.1.2. Automatic Property Expansion Using Gradle
您可以通过配置Java插件的process Resources
任务自动展开Gradle项目中的属性,如下例所示:
tasks.named('processResources') {
expand(project.properties)
}
然后可以使用占位符引用Gradle项目的属性,如下例所示:
app.name=${name}
app.description=${description}
Gradle’s expand method uses Groovy’s SimpleTemplateEngine , which transforms ${..} tokens. The ${..} style conflicts with Spring’s own property placeholder mechanism. To use Spring property placeholders together with automatic expansion, escape the Spring property placeholders as follows: \${..} . |
2.2. Externalize the Configuration of SpringApplication
SpringApplication
具有Bean属性设置器,因此您可以在创建应用程序时使用其Java API来修改其行为。或者,您可以通过设置spring.main.*
中的属性来外部化配置。例如,在Applation.Properties
中,您可能具有以下设置:
spring.main.web-application-type=none
spring.main.banner-mode=off
那么在启动时不会打印Spring Boot横幅,应用程序也不会启动嵌入式Web服务器。
外部配置中定义的属性覆盖和替换使用Java API指定的值,但主源除外。主要源代码是提供给SpringApplication
构造函数的源代码:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MyApplication.class); application.setBannerMode(Banner.Mode.OFF); application.run(args); } }
或发送到<代码>源文件(…)<代码>SpringApplicationBuilder方法:
public class MyApplication { public static void main(String[] args) { new SpringApplicationBuilder() .bannerMode(Banner.Mode.OFF) .sources(MyApplication.class) .run(args); } }
在上面的示例中,如果我们有以下配置:
spring.main.sources=com.example.MyDatabaseConfig,com.example.MyJmsConfig
spring.main.banner-mode=console
实际的应用程序将显示横幅(被配置覆盖),并为ApplicationContext
使用三个源。应用程序来源包括:
-
MyApplication
(来自代码) -
我的数据库配置
(来自外部配置) -
MyJmsConfig
(来自外部配置)
2.3. Change the Location of External Properties of an Application
默认情况下,来自不同来源的属性以定义的顺序添加到SpringEnvironment
中(有关确切顺序,请参阅‘Spring Boot Feature’一节中的“Feature ures.html”)。
您还可以提供以下系统属性(或环境变量)来更改行为:
-
spring.config.name
(SPUNG_CONFIG_NAME
):默认为应用程序
作为文件名的根。 -
spring.config.Location
(SpringCONFIG_LOCATION
):要加载的文件(如类路径资源或URL)。为该文档设置了单独的Environment
属性源,它可以被系统属性、环境变量或命令行覆盖。
无论您在环境中设置什么,Spring Boot始终加载Application.Properties
,如上所述。默认情况下,如果使用YAML,则扩展名为“.yml”的文件也会添加到列表中。
If you want detailed information about the files that are being loaded you can set the logging level of org.springframework.boot.context.config to trace . |
2.4. Use ‘Short’ Command Line Arguments
有些人喜欢(例如)使用--port=9000
而不是--server.port=9000
在命令行上设置配置属性。您可以通过在Application.Properties
中使用占位符来启用此行为,如下例所示:
server.port=${port:8080}
If you inherit from the spring-boot-starter-parent POM, the default filter token of the maven-resources-plugins has been changed from ${*} to @ (that is, @maven.token@ instead of ${maven.token} ) to prevent conflicts with Spring-style placeholders. If you have enabled Maven filtering for the application.properties directly, you may want to also change the default filter token to use other delimiters. |
In this specific case, the port binding works in a PaaS environment such as Heroku or Cloud Foundry. In those two platforms, the PORT environment variable is set automatically and Spring can bind to capitalized synonyms for Environment properties. |
2.5. Use YAML for External Properties
YAML是JSON的超集,因此是以分层格式存储外部属性的便捷语法,如下例所示:
spring:
application:
name: "cruncher"
datasource:
driver-class-name: "com.mysql.jdbc.Driver"
url: "jdbc:mysql://localhost/test"
server:
port: 9000
创建一个名为applation.yml
的文件,并将其放在类路径的根目录中。然后将Snakeyaml
添加到您的依赖项(Maven坐标org.yaml:snakeyaml
,如果您使用Spring-boot-starter
,就已经包含了)。YAML文件被解析为JavaMap<;字符串、对象
(类似于JSON对象),而Spring Boot将映射展平,以便它有一级深度并具有句点分隔的键,就像许多人习惯于使用Java中的Properties
文件一样。
前面的示例YAML对应于以下Applation.Properties
文件:
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
有关YAML的更多信息,请参见“Spring Boot特性”部分中的“Feature.html”。
2.6. Set the Active Spring Profiles
SpringEnvironment
有一个用于此的API,但您通常需要设置一个系统属性(spring.profiles.active
)或一个操作系统环境变量(SpringPROFILES_ACTIVE
)。此外,您还可以使用-D
参数启动应用程序(请记住将其放在主类或JAR归档文件之前),如下所示:
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
在Spring Boot中,您还可以在Application.Properties
中设置活动配置文件,如下例所示:
spring.profiles.active=production
以这种方式设置的值将被系统属性或环境变量设置替换,但不会被SpringApplicationBuilder.profiles()
方法替换。因此,后一种Java API可用于扩充配置文件,而无需更改缺省值。
有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。
2.7. Set the Default Profile Name
默认配置文件是在没有配置文件处于活动状态时启用的配置文件。默认情况下,默认配置文件的名称是Default
,但可以使用系统属性(spring.profiles.Default
)或操作系统环境变量(Spring_PROFILES_DEFAULT
)来更改它。
在Spring Boot中,您还可以在Application.Properties
中设置默认配置文件名称,如下例所示:
spring.profiles.default=dev
有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。
2.8. Change Configuration Depending on the Environment
Spring Boot支持多文档YAML和属性文件(有关详细信息,请参阅Feature ures.html),这些文件可以根据活动配置文件有条件地激活。
如果文档包含代码键,则配置文件值(以逗号分隔的配置文件列表或配置文件表达式)将被提供给Spring.Accept tsProfiles() spring.config.activate.on-profile>方法。如果配置文件表达式匹配,则该文档将包括在最终合并中(否则不包括),如下例所示:
server.port=9000
#---
spring.config.activate.on-profile=development
server.port=9001
#---
spring.config.activate.on-profile=production
server.port=0
在上例中,默认端口为9000。但是,如果名为‘Development’的Spring配置文件处于活动状态,则端口为9001。如果‘Products’处于活动状态,则端口为0。
The documents are merged in the order in which they are encountered. Later values override earlier values. |
2.9. Discover Built-in Options for External Properties
Spring Boot在运行时将来自Applation.Properties
(或.yml
文件和其他位置)的外部属性绑定到应用程序。在单个位置中没有(从技术上讲也不可能)列出所有受支持属性的详尽列表,因为贡献可以来自类路径上的其他JAR文件。
具有Actuator功能的运行应用程序有一个configprops
端点,该端点显示可通过@ConfigurationProperties
使用的所有绑定和可绑定属性。
附录包括一个application.properties
示例,其中列出了Spring Boot支持的最常见属性。确定的列表来自于在源代码中搜索@ConfigurationProperties
和@Value
注释,以及偶尔使用活页夹
。有关加载属性的确切顺序的详细信息,请参阅“Featureres.html”。
3. Embedded Web Servers
每个Spring Boot Web应用程序都包括一个嵌入式Web服务器。此功能导致了许多操作指南问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节回答了这些问题。
3.1. Use Another Web Server
许多Spring Boot启动器都包含默认的嵌入式容器。
-
对于Servlet堆栈应用程序,
SpringBoot-starter-web
通过包含Spring-boot-starter-tomcat
包括Tomcat,但您可以使用Spring-boot-starter-jetty
或Spring-ot-starter-undertow
。 -
对于反应式堆栈应用程序,
SpringBoot-starter-webFlux
通过包含spring-boot-starter-reactor-netty
,来包括反应器Netty,但是您可以使用Spring-Boot-starter-tomcat
、Spring-Boot-starter-jetty
或Spring-Boot-starter-undertow
。
当切换到不同的HTTP服务器时,您需要将默认依赖项替换为您需要的依赖项。为了帮助完成这个过程,Spring Boot为每个受支持的HTTP服务器提供了一个单独的启动器。
下面的Maven示例显示如何排除Tomcat而包含Jetty for Spring MVC:
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
The version of the servlet API has been overridden as, unlike Tomcat 9 and Undertow 2, Jetty 9.4 does not support servlet 4.0. |
如果您希望使用Jetty 10,它支持Servlet 4.0,则可以按以下示例所示进行操作:
<properties>
<jetty.version>10.0.8</jetty.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<exclusions>
<!-- Exclude the Jetty-9 specific dependencies -->
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
注意,除了排除Tomcat启动器之外,还需要排除几个特定于Jetty9的依赖项。
下面的Gradle示例配置了必要的依赖项和一个模块替换,以使用Undertow来替换Spring WebFlux的反应器Netty:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-undertow"
implementation "org.springframework.boot:spring-boot-starter-webflux"
modules {
module("org.springframework.boot:spring-boot-starter-reactor-netty") {
replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
}
}
}
spring-boot-starter-reactor-netty is required to use the WebClient class, so you may need to keep a dependency on Netty even when you need to include a different HTTP server. |
3.2. Disabling the Web Server
如果您的类路径包含启动Web服务器所需的位,则Spring Boot将自动启动它。要禁用此行为,请配置应用程序.Properties
中的WebApplicationType
,如下例所示:
spring.main.web-application-type=none
3.3. Change the HTTP Port
在独立应用程序中,主HTTP端口默认为8080
,但可以使用server.port
进行设置(例如,在Applation.Properties
中或作为系统属性)。由于Environment
值的松散绑定,您还可以使用SERVER_PORT
(例如,作为OS环境变量)。
要完全关闭HTTP端点,但仍然创建WebApplicationContext
,请使用server.port=-1
(这样做有时对测试很有用)。
有关更多详细信息,请参阅“Spring Boot特性”部分中的“web.html”,或ServerProperties
源代码。
3.5. Discover the HTTP Port at Runtime
您可以从日志输出或从WebServerApplicationContext
通过其WebServer
访问服务器正在运行的端口。获得它并确保它已被初始化的最好方法是添加一个ApplicationListener<;WebServerInitializedEvent>;
类型的<代码>@Bean
,并在发布时将容器从事件中拉出。
使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
的测试还可以通过使用<代码>@LocalServerPort
注释将实际端口注入到字段中,如下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class MyWebIntegrationTests { @LocalServerPort int port; // ... }
|
3.6. Enable HTTP Response Compression
Jetty、Tomcat、Reactive Netty和Undertow支持HTTP响应压缩。可以在Applation.Properties
中开启,如下所示:
server.compression.enabled=true
默认情况下,响应的长度必须至少为2048字节,才能执行压缩。您可以通过设置server.compression.min-response-size
属性来配置此行为。
默认情况下,只有当响应的内容类型为以下类型之一时,才会压缩响应:
-
text/html
-
Text/XML
-
文本/纯文本
-
文本/css
-
文本/Java脚本
-
应用程序/Java脚本
-
应用程序/json
-
应用程序/XML
您可以通过设置server.compression.MIME-Types
属性来配置此行为。
3.7. Configure SSL
可以通过设置各种server.ssl.*
属性来声明性地配置SSL,这些属性通常位于Application.Properties
或Application.yml
中。以下示例显示使用Java密钥库文件设置SSL属性:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
以下示例显示使用PEM编码的证书和私钥文件设置SSL属性:
server.port=8443
server.ssl.certificate=classpath:my-cert.crt
server.ssl.certificate-private-key=classpath:my-cert.key
server.ssl.trust-certificate=classpath:ca-cert.crt
有关所有受支持属性的详细信息,请参阅SSL
。
使用如上所述的配置意味着应用程序不再支持端口8080处的纯HTTP连接器。Spring Boot不支持通过Applation.Properties
配置HTTP连接器和HTTPS连接器。如果您想同时拥有两者,则需要以编程方式配置其中一个。我们建议使用Applation.Properties
来配置HTTPS,因为在两者中,通过编程配置HTTP连接器更容易。
3.8. Configure HTTP/2
您可以使用server.HTTP2.Enabled
配置属性在您的Spring Boot应用程序中启用HTTP/2支持。同时支持h2
(TLS上的HTTP/2)和h2c
(TCP上的HTTP/2)。若要使用H2
,还必须启用SSL。未启用SSL时,将使用h2c
。例如,当您的应用程序在执行TLS终止的代理服务器后面运行时,您可能希望使用h2c
。h2
支持的详细信息取决于所选的Web服务器和应用程序环境,因为并非所有JDK 8发行版都现成支持该协议。
3.8.1. HTTP/2 With Tomcat
默认情况下,Spring Boot附带Tomcat 9.0.x,当使用JDK 9或更高版本时,它支持开箱即用的h2c
和h2
。或者,如果libtcative
库及其依赖项安装在主机操作系统上,则可以在JDK 8上使用h2
。
库目录必须对JVM库路径可用(如果尚未提供)。您可以使用jvm参数来实现这一点,比如-Djava.library.path=/usr/local/opt/tomcat-native/lib
.有关这方面的更多信息,请参阅Tomcat官方文档。
在启用了HTTP/2和SSL的JDK 8上启动Tomcat 9.0.x,但不启用本机支持时,会记录以下错误:
ERROR 8787 --- [ main] o.a.coyote.http11.Http11NioProtocol : The upgrade handler [org.apache.coyote.http2.Http2Protocol] for [h2] only supports upgrade via ALPN but has been configured for the ["https-jsse-nio-8443"] connector that does not support ALPN.
此错误不是致命的,应用程序启动时仍支持HTTP/1.1 SSL。
3.8.2. HTTP/2 With Jetty
为了支持http/2,Jetty需要额外的org.eclipse.jetty.http2:http2-server
依赖项。若要使用h2c
,不需要其他依赖项。要使用h2
,您还需要根据您的部署选择以下依赖项之一:
-
适用于在JDK9+上运行的应用程序的
org.eclipse.jetty:jetty-alpn-java-server
-
用于在JDK8u252+上运行的应用程序的
org.eclipse.jetty:jetty-alpn-openjdk8-server
-
org.eclipse.jetty:jetty-alpn-conscrypt-server
和加密库,无需jdk
3.8.3. HTTP/2 With Reactor Netty
默认情况下,SpringBoot-WebFlux-starter
使用反应器Netty作为服务器。反应器Netty支持使用JDK 8或更高版本的h2c
,不需要额外的依赖项。反应器Netty使用JDK 9或更高版本的JDK支持来支持H2
。对于JDK 8环境或最佳运行时性能,该服务器还支持带有本地库的h2
。要实现这一点,您的应用程序需要有一个额外的依赖项。
Spring Boot管理io.netty:netty-tcnative-boringssl-static
“Uber JAR”的版本,其中包含所有平台的本地库。开发人员可以选择使用分类器仅导入所需的依赖项(参见Netty官方文档)。
3.9. Configure the Web Server
通常,您应该首先考虑使用众多可用配置密钥中的一个,并通过在Application.Properties
或Application.yml
文件中添加新条目来自定义您的Web服务器。请参阅“了解外部属性的内置选项”)。server.*
名称空间在这里非常有用,它包括server.tomcat.*
、server.jetty.*
等名称空间,用于特定于服务器的功能。请参阅应用程序-属性.html的列表。
前面的小节已经介绍了许多常见的用例,比如压缩、SSL语言或HTTP2。您可以声明这样的组件并访问与您的选择相关的服务器工厂:您应该为所选的服务器(Tomcat、Jetty、Reactive Netty、Undertow)和所选的Web堆栈(Servlet或Reactive)选择变体。
下面的示例针对的是带有Spring-boot-starter-web
(Servlet堆栈)的Tomcat:
@Component public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { // customize the factory here } }
Spring Boot uses that infrastructure internally to auto-configure the server. Auto-configured WebServerFactoryCustomizer beans have an order of 0 and will be processed before any user-defined customizers, unless it has an explicit order that states otherwise. |
一旦您使用定制器访问了WebServerFactory
,您就可以使用它来配置特定的部分,如连接器、服务器资源或服务器本身--所有这些都使用特定于服务器的API。
此外,Spring Boot还提供:
Server | Servlet stack | Reactive stack |
---|---|---|
汤姆猫 |
|
|
码头 |
|
|
暗流 |
|
|
反应堆 |
不适用 |
|
最后,您还可以声明自己的WebServerFactory
Bean,它将覆盖由Spring Boot提供的Bean。这样做时,自动配置的定制器仍将应用于您的定制工厂,因此请谨慎使用该选项。
3.10. Add a Servlet, Filter, or Listener to an Application
在Servlet堆栈应用程序中,即使用,有两种方法可以将Servlet
、Filter
、ServletContextListener
以及Servlet API支持的其他侦听器添加到您的应用程序中:
3.10.1. Add a Servlet, Filter, or Listener by Using a Spring Bean
要使用Spring Bean添加Servlet
、筛选器
或Servlet*Listener
,您必须为其提供@Bean
定义。当您想要注入配置或依赖项时,这样做可能非常有用。但是,您必须非常注意它们不会导致太多其他Bean的急切初始化,因为它们必须在应用程序生命周期的非常早的时候安装在容器中。(例如,让它们依赖于您的DataSource
或JPA配置不是一个好主意。)您可以通过在第一次使用时延迟初始化Bean来避免此类限制,而不是在初始化时进行。
对于筛选器和Servlet,您还可以通过添加FilterRegistrationBean
或ServletRegistrationBean
来代替或添加基础组件,从而添加映射和初始化参数。
如果筛选器注册没有指定 |
与任何其他Spring Bean一样,您可以定义Servlet过滤器Bean的顺序;请确保查看“web.html部分。
Disable Registration of a Servlet or Filter
正如前面所述,任何Servlet
或Filter
Bean都会自动注册到Servlet容器。要禁用特定筛选器
或Servlet
Bean的注册,请为其创建注册Bean并将其标记为已禁用,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyFilterConfiguration { @Bean public FilterRegistrationBean<MyFilter> registration(MyFilter filter) { FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter); registration.setEnabled(false); return registration; } }
3.11. Configure Access Logging
可以通过Tomcat、Undertow和Jetty各自的命名空间为它们配置访问日志。
例如,以下设置使用自定义模式记录Tomcat上的访问。
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms)
The default location for logs is a logs directory relative to the Tomcat base directory. By default, the logs directory is a temporary directory, so you may want to fix Tomcat’s base directory or use an absolute path for the logs. In the preceding example, the logs are available in my-tomcat/logs relative to the working directory of the application. |
Undertow的访问日志记录可以类似的方式进行配置,如下例所示:
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D ms)
server.undertow.options.server.record-request-start-time=true
请注意,除了启用访问日志记录并配置其模式外,还启用了记录请求开始时间。在访问日志模式中包括响应时间(%D
)时,这是必需的。日志存储在相对于应用程序工作目录的Logs
目录中。您可以通过设置server.underow.acceslog.dir
属性来自定义此位置。
最后,Jetty的访问日志也可以配置如下:
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log
默认情况下,日志被重定向到System.err
。有关更多详细信息,请参阅Jetty文档。
3.12. Running Behind a Front-end Proxy Server
如果您的应用程序在代理、负载均衡器或云中运行,则请求信息(如主机、端口、方案…花旗集团(:行情)可能会在此过程中发生变化.您的应用程序可能运行在10.10.10.10:8080
上,但HTTP客户端应该只看到example.org
。
RFC7239“Forwarded Headers”定义Forwarded
HTTP标头;代理可以使用该标头来提供有关原始请求的信息。您可以将应用程序配置为读取这些头文件,并在创建链接并将它们以HTTP302响应、JSON文档或HTML页面的形式发送给客户端时自动使用这些信息。还有非标准标头,如X-Forwarded-Host
、X-Forwarded-Port
、X-Forwarded-Proto
、X-Forwarded-SSL
和X-Forwarded-Prefix
。
如果代理添加了常用的X-Forwarded-For
和X-Forwarded-Proto
头,则将server.Forward-Headers-Strategy
设置为原生
就足以支持它们。使用此选项,Web服务器本身本身就支持此功能;您可以查看其特定文档以了解特定行为。
如果这还不够,Spring框架提供了一个ForwardedHeaderFilter。您可以将其注册为应用程序中的Servlet过滤器,方法是将server.ward-Headers-Strategy
设置为框架
。
If you are using Tomcat and terminating SSL at the proxy, server.tomcat.redirect-context-root should be set to false . This allows the X-Forwarded-Proto header to be honored before any redirects are performed. |
If your application runs in Cloud Foundry or Heroku, the server.forward-headers-strategy property defaults to NATIVE . In all other instances, it defaults to NONE . |
3.12.1. Customize Tomcat’s Proxy Configuration
如果您使用Tomcat,则可以额外配置用于携带转发信息的Header的名称,如下例所示:
server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header
Tomcat还配置了一个正则表达式,该表达式与要信任的内部代理相匹配。有关其默认值,请参阅附录中的server.tomcat.remoteip.internal-proxies
条目。您可以通过向Applation.Properties
添加条目来自定义阀门的配置,如下例所示:
server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
You can trust all proxies by setting the internal-proxies to empty (but do not do so in production). |
您可以通过关闭自动的RemoteIpValve来完全控制Tomcat的RemoteIpValve
的配置(为此,设置server.forward-headers-strategy=NONE
)并使用WebServerFactoryCustomizer
Bean添加一个新的阀实例。
3.13. Enable Multiple Connectors with Tomcat
您可以在<org.apache.catalina.connector.Connector
>TomcatServletWebServerFactory中添加一个连接器,可以支持多个连接器,包括http和HTTPS连接器,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyTomcatConfiguration { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() { return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createConnector()); } private Connector createConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setPort(8081); return connector; } }
3.14. Enable Tomcat’s MBean Registry
默认情况下,Embedded Tomcat的MBean注册表处于禁用状态。这最大限度地减少了Tomcat的内存占用。例如,如果要使用Tomcat的MBean,以便微米可以使用它们来公开指标,则必须使用server.tomcat.mbeanregistry.enabled
属性来执行此操作,如下例所示:
server.tomcat.mbeanregistry.enabled=true
3.15. Enable Multiple Listeners with Undertow
向UnderowServletWebServerFactory
添加一个UnderTower BuilderCustomizer
,向Builder
添加一个监听器,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyUndertowConfiguration { @Bean public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() { return (factory) -> factory.addBuilderCustomizers(this::addHttpListener); } private Builder addHttpListener(Builder builder) { return builder.addHttpListener(8080, "0.0.0.0"); } }
3.16. Create WebSocket Endpoints Using @ServerEndpoint
如果要在使用嵌入式容器的Spring Boot应用程序中使用@ServerEndpoint
,则必须声明一个ServerEndpoint Exporter
@Bean
,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyWebSocketConfiguration { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
上例中显示的Bean向底层WebSocket容器注册任何@ServerEndpoint
注释的Bean。当部署到独立的Servlet容器时,此角色由Servlet容器初始值设定项执行,ServerEndpointExporter
Bean不是必需的。
4. Spring MVC
Spring Boot有许多启动器,其中包括Spring MVC。请注意,一些初学者包含对Spring MVC的依赖,而不是直接包含它。本节回答了有关Spring MVC和Spring Boot的常见问题。
4.1. Write a JSON REST Service
默认情况下,只要Jackson2位于类路径上,Spring Boot应用程序中的任何Spring@RestController
都应该呈现JSON响应,如下例所示:
@RestController public class MyController { @RequestMapping("/thing") public MyThing thing() { return new MyThing(); } }
只要Mything
可以由Jackson2序列化(对于普通的POJO或Groovy对象为真),localhost:8080/thing
默认情况下提供它的JSON表示。请注意,在浏览器中,您有时可能会看到XML响应,因为浏览器倾向于发送首选XML的Accept标头。
4.2. Write an XML REST Service
如果类路径上有Jackson XML扩展名(jackson-dataFormat-xml
),则可以使用它来呈现XML响应。我们为JSON使用的前一个示例将会起作用。若要使用Jackson XML渲染器,请将以下依赖项添加到项目中:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
如果Jackson的XML扩展不可用,而JAXB可用,则可以呈现XML,但需要将Mything
注释为@XmlRootElement
,如下例所示:
@XmlRootElement public class MyThing { private String name; }
您需要确保JAXB库是项目的一部分,例如,通过添加:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
To get the server to render XML instead of JSON, you might have to send an Accept: text/xml header (or use a browser). |
4.3. Customize the Jackson ObjectMapper
Spring MVC(客户端和服务器端)使用HttpMessageConverters
协商HTTP交换中的内容转换。如果Jackson在类路径上,那么您已经获得了由Jackson2ObjectMapperBuilder
提供的默认转换器,它的一个实例是自动配置的。
默认情况下创建的ObjectMapper
(或用于Jackson XML转换器的XmlMapper
)实例具有以下自定义属性:
-
MapperFeature.DEFAULT_VIEW_INCLUSION
已禁用 -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
已禁用 -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
已禁用
Spring Boot还具有一些功能,可以更轻松地自定义此行为。
您可以使用该环境配置ObjectMapper
和XmlMapper
实例。Jackson提供了一套广泛的开/关功能,可用于配置其处理的各个方面。这些功能在六个枚举(在Jackson中)中进行了描述,它们映射到环境中的属性:
Enum | Property | Values |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,要启用漂亮打印,请设置spring.jackson.serialization.indent_output=true
.请注意,由于使用了松散绑定,INDENT_OUTPUT
的大小写不必与相应的枚举常量(INDENT_OUTPUT
)的大小写匹配。
此基于环境的配置应用于自动配置的Jackson2ObjectMapperBuilder
Bean,并应用于使用构建器创建的任何映射器,包括自动配置的ObjectMapper
Bean。
上下文的Jackson2ObjectMapperBuilder
可以由一个或多个Jackson2ObjectMapperBuilderCustomizer
Bean自定义。这样的定制器Bean可以订购(Boot自己的定制器的顺序为0),允许在Boot的定制之前和之后应用额外的定制。
任何com.fasterxml.jackson.databind.Module
类型的Bean都会自动注册到自动配置的Jackson2ObjectMapperBuilder
,并应用于它创建的任何对象映射器
实例。这提供了一种全局机制,用于在向应用程序添加新功能时贡献自定义模块。
如果您想要完全替换默认的对象映射器
,可以定义该类型的@Bean
并将其标记为@Primary
,或者,如果您更喜欢基于构建器的方法,则定义一个Jackson2ObjectMapperBuilder
@Bean
。请注意,在任何一种情况下,这样做都会禁用对象映射器
的所有自动配置。
如果您提供任何MappingJackson2HttpMessageConverter
,类型的<代码>@Bean
,它们将替换MVC配置中的缺省值。此外,还提供了HttpMessageConverters
类型的便利Bean(如果您使用默认的MVC配置,则该Bean始终可用)。它有一些有用的方法来访问默认的和用户增强的消息转换器。
有关更多详细信息,请参阅定制@ResponseBody呈现一节和WebMvcAutoConfiguration
源代码。
4.4. Customize the @ResponseBody Rendering
Spring使用HttpMessageConverters
来呈现@ResponseBody
(或来自@RestController
的响应)。您可以通过在Spring Boot上下文中添加适当类型的Bean来贡献额外的转换器。如果您添加的Bean属于缺省包含的类型(例如用于JSON转换的MappingJackson2HttpMessageConverter
),它将替换缺省值。提供了一个HttpMessageConverters
类型的便利Bean,如果您使用默认的MVC配置,则该Bean始终可用。它有一些有用的方法来访问默认的和用户增强的消息转换器(例如,如果您想要手动将它们注入到自定义的RestTemplate
中,它可能会很有用)。
与正常的MVC使用一样,您提供的任何WebMvcConfigurer
Bean也可以通过覆盖figureMessageConverters
方法来提供转换器。然而,与普通的MVC不同,您只能提供所需的附加转换器(因为Spring Boot使用相同的机制来提供其缺省值)。最后,如果您通过提供自己的@EnableWebMvc
配置退出了Spring Boot默认MVC配置,则可以完全控制并通过使用WebMvcConfigurationSupport
中的
getMessageConverters
手动完成所有操作。
有关更多详细信息,请参阅WebMvcAutoConfiguration
源代码。
4.5. Handling Multipart File Uploads
Spring Boot采用Servlet 5jakarta.servlet.http.Part
API来支持文件上传。默认情况下,Spring Boot将Spring MVC配置为每个文件的最大大小为1MB,单个请求中的文件数据最大为10MB。您可以使用MultipartProperties
类中公开的属性来覆盖这些值、存储中间数据的位置(例如,存储到/tmp
目录中)和数据刷新到磁盘的阈值。例如,如果要指定文件不受限制,请将spring.servlet.multipart.max-file-size
属性设置为<代码>-1
。
当您希望在Spring MVC控制器处理程序方法中将多部分编码文件数据作为@RequestParam
类型的带注释的参数MultipartFile
接收时,多部分支持很有帮助。
有关更多详细信息,请参阅MultipartAutoConfiguration
源代码。
It is recommended to use the container’s built-in support for multipart uploads rather than introducing an additional dependency such as Apache Commons File Upload. |
4.6. Switch Off the Spring MVC DispatcherServlet
默认情况下,所有内容都从应用程序的根(/
)提供。如果您希望映射到其他路径,则可以按如下方式配置一条路径:
spring.mvc.servlet.path=/mypath
如果您有其他的Servlet,您可以为每个Servlet声明一个@Bean
类型的ServletRegistrationBean
,而Spring Boot将透明地将它们注册到容器。因为Servlet是以这种方式注册的,所以可以将它们映射到DispatcherServlet
的子上下文,而无需调用它。
自己配置DispatcherServlet
并不常见,但如果您确实需要这样做,则还必须提供DispatcherServletPath
类型的@Bean
,以提供您的自定义DispatcherServlet
的路径。
4.7. Switch off the Default MVC Configuration
完全控制MVC配置的最简单方法是为您自己的@configuration
提供@EnableWebMvc
注释。这样做会让您掌握所有MVC配置。
4.8. Customize ViewResolvers
ViewResolver
是Spring MVC的核心组件,它将@Controller
中的视图名称转换为实际的View
实现。请注意,ViewResolver
主要用于UI应用程序,而不是REST样式的服务(View
不用于呈现@ResponseBody
)。有许多ViewResolver
的实现可供选择,而Spring本身并不坚持您应该使用哪些实现。另一方面,Spring Boot根据它在类路径和应用程序上下文中找到的内容,为您安装一个或两个。DispatcherServlet
使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器,直到得到结果。如果你添加你自己的,你必须知道你的解析器的添加顺序和位置。
WebMvcAutoConfiguration
将以下ViewResolver
添加到您的上下文中:
-
名为“defaultViewResolver”的
InternalResourceViewResolver
。它定位可以使用DefaultServlet
呈现的物理资源(包括静态资源和JSP页面,如果您使用它们的话)。它将前缀和后缀应用于视图名,然后在Servlet上下文中查找具有该路径的物理资源(缺省值均为空,但可通过spring.mvc.view.prefix
和spring.mvc.view.Suffix
进行外部配置)。您可以通过提供相同类型的Bean来覆盖它。 -
名为‘beanNameViewResolver’的
BeanNameViewResolver
。这是视图解析器链中有用的成员,并获取与被解析的视图
同名的任何Bean。应该没有必要覆盖或替换它。 -
仅当实际存在
View
类型的Bean时,才会添加名为“”viewResolver“”的Content NeatheratingViewResolver
。“”这是一个复合解析器,委托给所有其他解析器,并尝试查找与客户端发送的‘Accept’HTTP头匹配的内容。有一个关于ContentNegotiatingViewResolver
的有用的博客,您可能想要学习它以了解更多,您也可以查看源代码以获取详细信息。您可以通过定义一个名为‘viewResolver’的Bean来关闭自动配置的ContentNeatheratingViewResolver
。 -
如果您使用Thymeleaf,您还拥有一个名为‘ThymeleafViewResolver’的
ThymeleafViewResolver
。它通过用前缀和后缀将视图名括起来来查找资源。前缀为spring.thoreleaf.prefix
,后缀为spring.thoreleaf.Suffix
。前缀和后缀的值默认为‘classpath:/plates/’和‘.html’。您可以通过提供同名的Bean来覆盖ThymeleafViewResolver
。 -
如果您使用的是FreeMarker,则还会有一个名为“freMarkerViewResolver”的
FreeMarkerViewResolver
。它通过使用前缀和后缀将视图名括起来,在加载器路径(外部化到spring.freemarker.templateLoaderPath
,缺省值为‘classpath:/Templates/’)中查找资源。前缀被外部化为spring.freemarker.prefix
,后缀外部化为spring.freemarker.Suffix
。前缀和后缀的默认值分别为空和‘.ftlh’。您可以通过提供同名的Bean来覆盖FreeMarkerViewResolver
。 -
如果您使用Groovy模板(实际上,如果您的类路径上有
groovy-plates
),那么您还有一个名为‘groovyMarkupViewResolver’的GroovyMarkupViewResolver。它通过将视图名加上前缀和后缀(外部化为
spring.groovy.template.prefix
和spring.groovy.template.Suffix
)来查找加载器路径中的资源。前缀和后缀的缺省值分别为‘classpath:/plates/’和‘.tpl’。您可以通过提供同名的Bean来覆盖GroovyMarkupViewResolver
。 -
如果您使用Mustache,您还将拥有一个名为‘mustaheViewResolver’的
MustaheViewResolver
。它通过用前缀和后缀将视图名括起来来查找资源。前缀为spring.musta he.prefix
,后缀为spring.musta he.Suffix
。前缀和后缀的值默认为‘classpath:/Templates/’和‘.masache’。您可以通过提供同名的Bean来覆盖MustaheViewResolver
。
有关更多详细信息,请参阅以下各节:
5. Jersey
5.1. Secure Jersey endpoints with Spring Security
Spring Security可以用来保护基于Jersey的Web应用程序的安全,就像它可以用来保护基于Spring MVC的Web应用程序一样。但是,如果您希望在Jersey中使用Spring Security的方法级安全性,则必须将Jersey配置为使用setStatus(Int)
而不是sendError(Int)
。这可以防止Jersey在Spring Security有机会向客户端报告身份验证或授权失败之前提交响应。
必须在应用程序的资源配置
Bean上将jersey.config.server.response.setStatusOverSendError
属性设置为True
,如下例所示:
@Component public class JerseySetStatusOverSendErrorConfig extends ResourceConfig { public JerseySetStatusOverSendErrorConfig() { register(Endpoint.class); setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true)); } }
5.2. Use Jersey Alongside Another Web Framework
要将Jersey与其他Web框架(如Spring MVC)一起使用,应该对其进行配置,以便允许其他框架处理它无法处理的请求。首先,通过将spring.Jersey.type
应用程序属性的值配置为Filter
,将Jersey配置为使用筛选器而不是Servlet。其次,配置您的资源配置
以转发可能导致404的请求,如下例所示。
@Component public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(Endpoint.class); property(ServletProperties.FILTER_FORWARD_ON_404, true); } }
6. HTTP Clients
Spring Boot提供了许多可以与HTTP客户端一起工作的启动器。本节回答与使用它们相关的问题。
6.1. Configure RestTemplate to Use a Proxy
如io.html中所述,您可以使用RestTemplateCustomizer
和RestTemplateBuilder
来构建定制的RestTemplateCustomizer
。这是创建配置为使用代理的RestTemplate
的推荐方法。
代理配置的确切细节取决于正在使用的底层客户端请求工厂。
6.2. Configure the TcpClient used by a Reactor Netty-based WebClient
当反应器Netty位于类路径上时,将自动配置基于反应器Netty的WebClient
。要定制客户端对网络连接的处理,请提供一个ClientHttpConnector
Bean。以下示例配置60秒连接超时并添加ReadTimeoutHandler
:
@Configuration(proxyBeanMethods = false) public class MyReactorNettyClientConfiguration { @Bean ClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) { HttpClient httpClient = HttpClient.create(resourceFactory.getConnectionProvider()) .runOn(resourceFactory.getLoopResources()) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000) .doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60))); return new ReactorClientHttpConnector(httpClient); } }
Note the use of ReactorResourceFactory for the connection provider and event loop resources. This ensures efficient sharing of resources for the server receiving requests and the client making requests. |
7. Logging
除了Commons Logging API之外,Spring Boot没有强制的日志依赖项,该API通常由Spring框架的Spring-JCL
模块提供。要使用Logback,您需要在类路径中包含它和Spring-JCL
。推荐的方法是通过启动器,它们都依赖于Spring-ot-starter-Logging
。对于Web应用程序,您只需要Spring-boot-starter-web
,因为它过渡地依赖于日志记录启动器。如果您使用Maven,以下依赖项将为您添加日志记录:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot有一个LoggingSystem
抽象,它试图根据类路径的内容配置日志记录。如果Logback可用,则它是首选。
如果您需要对日志记录进行的唯一更改是设置各种记录器的级别,则可以在Application.Properties
中使用“logging.Level”前缀来执行此操作,如下例所示:
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
您还可以使用logging.file.name
设置要将日志写入到的文件的位置(除了控制台)。
要配置日志系统的更细粒度的设置,您需要使用所讨论的LoggingSystem
支持的本机配置格式。默认情况下,Spring Boot从系统的默认位置(如classpath:logback.xml
用于Logback)获取本机配置,但您可以使用logging.config
属性设置配置文件的位置。
7.1. Configure Logback for Logging
如果您需要对Logback应用定制,而不是使用Application.Properties
可以实现的定制,则需要添加一个标准的Logback配置文件。您可以将logback.xml
文件添加到类路径的根目录中,以供Logback查找。如果您想要使用Spring Boot Logback扩展,还可以使用logback-spring.xml
。
The Logback documentation has a dedicated section that covers configuration in some detail. |
Spring Boot提供了许多可以包含在您自己的配置中的Logback配置。这些包含旨在允许重新应用某些常见的Spring Boot约定。
org/springframework/boot/logging/logback/
:下提供了以下文件
-
defaults.xml
-提供转换规则、模式属性和通用记录器配置。 -
ConsoleAppendder.xml
-使用控制台_日志_模式
添加ConsoleAppender
。 -
使用
FILE_LOG_Patterns
和Rolling_FILE_NAME_Pattern
添加一个RollingFileAppender
。
此外,为了与早期版本的Spring Boot兼容,还提供了一个遗留的base.xml
文件。
典型的自定义logback.xml
文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
您的Logback配置文件还可以使用LoggingSystem
负责为您创建的系统属性:
-
${id}
:当前进程ID。 -
${log_file}
:是否在Boot的外部配置中设置了logging.file.name
。 -
${LOG_PATH}
:是否在Boot的外部配置中设置了logging.file.path
(表示存放日志文件的目录)。 -
${LOG_EXCEPTION_CONVERSION_WORD}
:是否在引导的外部配置中设置了logging.exception-conversion-word
。 -
${ROLING_FILE_NAME_PROPERT}
:是否在Boot的外部配置中设置了logging.pattern.rolling-file-name
。
通过使用定制的Logback转换器,Spring Boot还在控制台上(但不是在日志文件中)提供一些不错的ANSI色彩终端输出。有关示例,请参阅defaults.xml
配置中的控制台_日志_模式
。
如果Groovy位于类路径上,您也应该能够使用logback.groovy
配置Logback。如果存在,则优先考虑此设置。
Spring extensions are not supported with Groovy configuration. Any logback-spring.groovy files will not be detected. |
7.1.1. Configure Logback for File-only Output
如果要禁用控制台日志记录并仅将输出写入文件,则需要一个自定义Logback-spring.xml
,该文件可导入文件-appendder.xml
,但不能导入控制台-appendder.xml
,如下例所示:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
您还需要将logging.file.name
添加到您的applation.Properties
或applation.yaml
中,如下例所示:
logging.file.name=myapplication.log
7.2. Configure Log4j for Logging
如果位于类路径上,Spring Boot支持Log4j 2进行日志配置。如果使用启动器组装依赖项,则必须排除Logback,然后改为包含log4j 2。如果您不使用启动器,那么除了Log4j2之外,您还需要(至少)提供Spring-JCL
。
推荐的路径是通过起动器,尽管这需要一些抖动。以下示例显示如何在Maven中设置启动器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Gradle提供了几种不同的方法来设置启动器。一种方法是使用模块替换。为此,请声明对Log4j 2 Starter的依赖项,并告诉Gradle,任何出现的默认日志记录Starter都应替换为Log4j 2 Starter,如下例所示:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-log4j2"
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
}
}
}
The Log4j starters gather together the dependencies for common logging requirements (such as having Tomcat use java.util.logging but configuring the output using Log4j 2). |
To ensure that debug logging performed using java.util.logging is routed into Log4j 2, configure its JDK logging adapter by setting the java.util.logging.manager system property to org.apache.logging.log4j.jul.LogManager . |
7.2.1. Use YAML or JSON to Configure Log4j 2
除了默认的XML配置格式,Log4j 2还支持YAML和JSON配置文件。要将Log4j 2配置为使用替代配置文件格式,请将适当的依赖项添加到类路径,并命名配置文件以匹配您选择的文件格式,如下例所示:
Format | Dependencies | File names |
---|---|---|
YAML |
|
|
杰森 |
|
|
8. Data Access
Spring Boot包括许多用于使用数据源的启动器。本节回答与此相关的问题。
8.1. Configure a Custom DataSource
要配置您自己的DataSource
,请在您的配置中定义该类型的@Bean
。Spring Boot在任何需要的地方重用您的DataSource
,包括数据库初始化。如果您需要外部化某些设置,您可以将DataSource
绑定到环境(请参阅“Featureres.html”)。
以下示例显示如何在Bean中定义数据源:
@Configuration(proxyBeanMethods = false) public class MyDataSourceConfiguration { @Bean @ConfigurationProperties(prefix = "app.datasource") public SomeDataSource dataSource() { return new SomeDataSource(); } }
下面的示例说明如何通过设置属性来定义数据源:
app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30
假设SomeDataSource
具有URL、用户名和池大小的常规JavaBean属性,则在DataSource
可用于其他组件之前自动绑定这些设置。
Spring Boot还提供了一个实用程序构建器类,名为DataSourceBuilder
,可用于创建标准数据源之一(如果它位于类路径上)。构建器可以根据类路径上可用的内容来检测要使用的类路径。它还根据JDBC URL自动检测驱动程序。
下面的示例显示如何使用DataSourceBuilder
创建数据源:
@Configuration(proxyBeanMethods = false) public class MyDataSourceConfiguration { @Bean @ConfigurationProperties("app.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } }
要运行具有该数据源
的应用程序,您只需要连接信息。还可以提供特定于池的设置。有关更多详细信息,请查看将在运行时使用的实现。
下面的示例显示如何通过设置属性来定义JDBC数据源:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
然而,这其中有一个问题。因为没有公开连接池的实际类型,所以不会在您的自定义DataSource
的元数据中生成键,并且在您的IDE中没有可用的完成(因为DataSource
接口不公开任何属性)。此外,如果您碰巧在类路径上有Hikari,则这个基本设置不起作用,因为Hikari没有url
属性(但有一个jdbcUrl
属性)。在这种情况下,您必须重写配置,如下所示:
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
您可以通过强制连接池使用并返回专用实现而不是DataSource
来修复该问题。您不能在运行时更改实现,但选项列表将是明确的。
以下示例显示如何使用DataSourceBuilder
创建HikariDataSource
:
@Configuration(proxyBeanMethods = false) public class MyDataSourceConfiguration { @Bean @ConfigurationProperties("app.datasource") public HikariDataSource dataSource() { return DataSourceBuilder.create().type(HikariDataSource.class).build(); } }
您甚至可以进一步利用< >DataSourceProperties
为您提供的URL-URL,即在没有提供URL的情况下提供具有合理用户名和密码的默认嵌入式数据库。您可以很容易地从任何DataSourceProperties
对象的状态初始化DataSourceBuilder
,因此您还可以注入Spring Boot自动创建的数据源。但是,这会将您的配置分成两个名称空间:url
、用户名
、密码
、type
和spring.data ource
上的驱动程序
,其余的在您的自定义名称空间(app.datource
)上。为避免出现这种情况,您可以在自定义命名空间上重新定义自定义DataSourceProperties
,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyDataSourceConfiguration { @Bean @Primary @ConfigurationProperties("app.datasource") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Bean @ConfigurationProperties("app.datasource.configuration") public HikariDataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); } }
此设置使与Spring Boot在默认情况下为您执行的操作保持同步,只是(在代码中)选择了一个专用连接池,并且其设置在app.datource.configuration
子名称空间中公开。由于DataSourceProperties
会为您处理url
/jdbcUrl
翻译,因此您可以按如下方式进行配置:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
Spring Boot will expose Hikari-specific settings to spring.datasource.hikari . This example uses a more generic configuration sub namespace as the example does not support multiple datasource implementations. |
Because your custom configuration chooses to go with Hikari, app.datasource.type has no effect. In practice, the builder is initialized with whatever value you might set there and then overridden by the call to .type() . |
有关更多详细信息,请参阅“Spring Boot特性”部分中的“data.html和DataSourceAutoConfiguration
类。
8.2. Configure Two DataSources
如果您需要配置多个数据源,则可以应用上一节中描述的相同技巧。但是,您必须将其中一个DataSource
实例标记为@Primary
,因为以后的各种自动配置都希望能够按类型获取一个。
如果您创建自己的DataSource
,自动配置就会退出。在以下示例中,我们提供了与自动配置在主数据源上提供的完全相同的功能集:
@Configuration(proxyBeanMethods = false) public class MyDataSourcesConfiguration { @Bean @Primary @ConfigurationProperties("app.datasource.first") public DataSourceProperties firstDataSourceProperties() { return new DataSourceProperties(); } @Bean @Primary @ConfigurationProperties("app.datasource.first.configuration") public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) { return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); } @Bean @ConfigurationProperties("app.datasource.second") public BasicDataSource secondDataSource() { return DataSourceBuilder.create().type(BasicDataSource.class).build(); } }
firstDataSourceProperties has to be flagged as @Primary so that the database initializer feature uses your copy (if you use the initializer). |
这两个数据源还绑定了高级定制。例如,您可以按如下方式配置它们:
app.datasource.first.url=jdbc:mysql://localhost/first
app.datasource.first.username=dbuser
app.datasource.first.password=dbpass
app.datasource.first.configuration.maximum-pool-size=30
app.datasource.second.url=jdbc:mysql://localhost/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30
您也可以将相同的概念应用于辅助DataSource
,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyCompleteDataSourcesConfiguration { @Bean @Primary @ConfigurationProperties("app.datasource.first") public DataSourceProperties firstDataSourceProperties() { return new DataSourceProperties(); } @Bean @Primary @ConfigurationProperties("app.datasource.first.configuration") public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) { return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); } @Bean @ConfigurationProperties("app.datasource.second") public DataSourceProperties secondDataSourceProperties() { return new DataSourceProperties(); } @Bean @ConfigurationProperties("app.datasource.second.configuration") public BasicDataSource secondDataSource( @Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) { return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource.class).build(); } }
前面的示例使用与Spring Boot在自动配置中使用的相同逻辑在自定义命名空间上配置两个数据源。请注意,每个配置
子命名空间都提供基于所选实现的高级设置。
8.3. Use Spring Data Repositories
Spring Data可以创建各种风格的@Repository
接口的实现。只要这些@repositories
包含在您的@EnableAutoConfiguration
类的同一个包(或子包)中,Spring Boot就会为您处理所有这些问题。
对于许多应用程序,您所需要的就是将正确的Spring数据依赖项放在类路径上。有针对JPA的Spring-ot-starter-data-jpa
,针对MongoDB的Spring-ot-starter-data-MongoDB
,以及用于支持的技术的各种其他启动器。首先,创建一些存储库接口来处理您的@Entity
对象。
Spring Boot试图根据它找到的@EnableAutoConfiguration
猜测@Repository
定义的位置。要获得更多控制,请使用@EnableJpaRepositories
注释(来自Spring data JPA)。
有关Spring数据的更多信息,请参阅Spring data项目页面。
8.4. Separate @Entity Definitions from Spring Configuration
Spring Boot根据它找到的@EnableAutoConfiguration
尝试猜测@EnableEntity
定义的位置。要获得更多控制,可以使用@EntityScan
注释,如下例所示:
@Configuration(proxyBeanMethods = false) @EnableAutoConfiguration @EntityScan(basePackageClasses = City.class) public class MyApplication { // ... }
8.5. Configure JPA Properties
Spring data JPA已经提供了一些独立于供应商的配置选项(比如用于SQL日志记录的选项),而Spring Boot将这些选项和一些更多的Hibernate选项公开为外部配置属性。其中一些是根据上下文自动检测的,因此您应该不必设置它们。
spring.jpa.hibernate.ddl-auto
是一个特例,因为根据运行时条件的不同,它具有不同的缺省值。如果使用嵌入式数据库,并且没有模式管理器(如Liquibase或Flyway)正在处理DataSource
,则默认为Create-Drop
。在所有其他情况下,它默认为None
。
要使用的方言由JPA提供程序检测。如果您希望自己设置方言,请设置spring.jpa.database-Platform
属性。
要设置的最常见选项如下例所示:
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true
此外,在创建本地EntityManagerFactory
时,spring.jpa.Properties.*<
中的所有属性都作为普通JPA属性传递(去掉前缀)。
您需要确保 例如,如果您想要配置Hibernate的批处理大小,则必须使用 |
If you need to apply advanced customization to Hibernate properties, consider registering a HibernatePropertiesCustomizer bean that will be invoked prior to creating the EntityManagerFactory . This takes precedence to anything that is applied by the auto-configuration. |
8.6. Configure Hibernate Naming Strategy
Hibernate使用两种不同的命名策略将对象模型中的名称映射到相应的数据库名称。物理和隐式策略实现的完全限定类名可以分别通过设置spring.jpa.hibernate.naming.physical-strategy
和spring.jpa.hibernate.naming.implicit-strategy
属性来配置。或者,如果应用程序上下文中有ImplittNamingStrategy
或PhysicalNamingStrategy
Bean可用,则Hibernate将自动配置为使用它们。
默认情况下,Spring Boot使用CamelCaseToUnderscoresNamingStrategy
.配置物理命名策略使用这种策略,所有的点都被下划线取代,驼峰大小写也被下划线取代。此外,默认情况下,所有表名都以小写形式生成。例如,TelephoneNumber
实体被映射到Telephone_Number
表。如果您的架构需要大小写混合的标识符,请定义一个自定义CamelCaseToUnderscoresNamingStrategy
Bean,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyHibernateConfiguration { @Bean public CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() { return new CamelCaseToUnderscoresNamingStrategy() { @Override protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) { return false; } }; } }
如果您更喜欢使用Hibernate 5的默认设置,请设置以下属性:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
或者,您可以配置以下Bean:
@Configuration(proxyBeanMethods = false) class MyHibernateConfiguration { @Bean PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() { return new PhysicalNamingStrategyStandardImpl(); } }
有关更多详细信息,请参阅HibernateJpaAutoConfiguration
和JpaBaseConfiguration
。
8.7. Configure Hibernate Second-Level Caching
可以为一系列缓存提供者配置Hibernate二级缓存。与其将Hibernate配置为再次查找缓存提供程序,不如尽可能提供上下文中可用的缓存提供程序。
要使用jCache来实现这一点,首先要确保类路径上有可用的org.hibernate.orm:hibernate-jcache
。然后,添加一个HibernatePropertiesCustomizer
Bean,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyHibernateSecondLevelCacheConfiguration { @Bean public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) { return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager()); } }
此定制器将配置Hibernate,使其使用与应用程序相同的CacheManager
。也可以使用单独的CacheManager
实例。有关详细信息,请参阅Hibernate用户指南。
8.8. Use Dependency Injection in Hibernate Components
默认情况下,Spring Boot注册一个使用BeanFactory
的BeanContainer
实现,以便转换器和实体侦听器可以使用常规的依赖项注入。
您可以通过注册移除或更改hibernate.resource.beans.container
属性的<代码>HibernatePropertiesCustomizer来禁用或调整此行为。
8.9. Use a Custom EntityManagerFactory
若要完全控制EntityManagerFactory
的配置,您需要添加一个名为“entityManagerFactory”的@Bean
。当存在该类型的Bean时,Spring Boot自动配置会关闭其实体管理器。
8.10. Using Multiple EntityManagerFactories
如果您需要对多个数据源使用JPA,则每个数据源可能需要一个EntityManagerFactory
。来自Spring ORM的代码允许您根据需要配置<LocalContainerEntityManagerFactoryBean
>EntityManager Factory。您还可以重用JpaProperties
来绑定每个EntityManagerFactory
的设置,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyEntityManagerFactoryConfiguration { @Bean @ConfigurationProperties("app.jpa.first") public JpaProperties firstJpaProperties() { return new JpaProperties(); } @Bean public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource, JpaProperties firstJpaProperties) { EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties); return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build(); } private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) { JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties); return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null); } private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) { // ... map JPA properties as needed return new HibernateJpaVendorAdapter(); } }
上面的示例使用名为FirstDataSource
的DataSource
创建了一个EntityManagerFactory
。它扫描与Order
位于同一包中的实体。可以使用app.first st.jpa
命名空间映射其他JPA属性。
When you create a bean for LocalContainerEntityManagerFactoryBean yourself, any customization that was applied during the creation of the auto-configured LocalContainerEntityManagerFactoryBean is lost. For example, in case of Hibernate, any properties under the spring.jpa.hibernate prefix will not be automatically applied to your LocalContainerEntityManagerFactoryBean . If you were relying on these properties for configuring things like the naming strategy or the DDL mode, you will need to explicitly configure that when creating the LocalContainerEntityManagerFactoryBean bean. |
您应该为需要JPA访问的任何其他数据源提供类似的配置。为了完成这幅图,您还需要为每个EntityManagerFactory
配置一个JpaTransactionManager
。或者,您也可以使用跨两者的JTA事务管理器。
如果您使用的是Spring数据,则需要相应地配置@EnableJpaRepositories
,如下例所示:
@Configuration(proxyBeanMethods = false) @EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "firstEntityManagerFactory") public class OrderConfiguration { }
@Configuration(proxyBeanMethods = false) @EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory") public class CustomerConfiguration { }
8.11. Use a Traditional persistence.xml File
默认情况下,Spring Boot不会搜索或使用META-INF/Persistence.xml
。如果您更喜欢使用传统的sistence.xml
,则需要定义您自己的@Bean
类型的LocalEntityManagerFactoryBean
(ID为‘entityManagerFactory’),并在其中设置持久性单元名称。
有关默认设置,请参阅JpaBaseConfiguration
。
8.12. Use Spring Data JPA and Mongo Repositories
Spring data JPA和Spring data Mongo都可以自动为您创建Repository
实现。如果它们都出现在类路径上,您可能需要做一些额外的配置来告诉Spring Boot要创建哪个存储库。要做到这一点,最明确的方法是使用标准的Spring数据@EnableJpaRepositories
和@EnableMongoRepositories
注释,并提供Repository
接口的位置。
还有标志(spring.data.*.repositories.enabled
和spring.data.*.repositories.type
,您可以使用它们在外部配置中打开和关闭自动配置的存储库。例如,如果您想要关闭Mongo存储库而仍然使用自动配置的MongoTemplate
,这样做很有用。
对于其他自动配置的Spring数据存储库类型(Elasticearch、Solr等),也存在相同的障碍和相同的功能。要使用它们,请相应地更改注释和标志的名称。
8.13. Customize Spring Data’s Web Support
Spring Data提供了Web支持,简化了在Web应用程序中使用Spring数据存储库。Spring Boot在spring.data.web
命名空间中提供了用于定制其配置的属性。请注意,如果您使用的是Spring data rest,则必须改用spring.data.rest
名称空间中的属性。
8.14. Expose Spring Data Repositories as REST Endpoint
只要为应用程序启用了Spring MVC,Spring data rest可以将Repository
实现公开为您的REST端点。
Spring Boot公开了一组有用的属性(来自
RepositoryRestConfiguration
.>spring.data.rest命名空间),用于定制
RepositoryRestConfigurer
Bean。
If you do not specify any order on your custom RepositoryRestConfigurer , it runs after the one Spring Boot uses internally. If you need to specify an order, make sure it is higher than 0. |
8.15. Configure a Component that is Used by JPA
如果您想要配置JPA使用的组件,那么您需要确保在JPA之前初始化该组件。当组件被自动配置时,Spring Boot会为您处理这一点。例如,当Flyway被自动配置时,Hibernate被配置为依赖于Flyway,这样Flyway就有机会在Hibernate尝试使用它之前初始化数据库。
如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor
子类作为设置必要依赖项的便捷方法。例如,如果您使用Hibernate Search并将Elasticearch作为其索引管理器,则必须将任何EntityManagerFactory
Bean配置为依赖于弹性搜索客户端
Bean,如下例所示:
/** * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean. */ @Component public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor extends EntityManagerFactoryDependsOnPostProcessor { public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() { super("elasticsearchClient"); } }
8.16. Configure jOOQ with Two DataSources
如果您需要将jOOQ与多个数据源一起使用,则应该为每个数据源创建自己的DSLContext
。有关详细信息,请参阅JooqAutoConfiguration。
In particular, JooqExceptionTranslator and SpringTransactionProvider can be reused to provide similar features to what the auto-configuration does with a single DataSource . |
9. Database Initialization
根据堆栈的不同,可以以不同的方式初始化SQL数据库。当然,您也可以手动完成此操作,前提是数据库是一个单独的进程。建议使用单一的模式生成机制。
9.1. Initialize a Database Using JPA
JPA具有用于生成DDL的特性,这些特性可以设置为在数据库启动时运行。这是通过两个外部属性控制的:
-
spring.jpa.Generate-ddl
(Boolean)打开和关闭该功能,并且独立于供应商。 -
spring.jpa.hibernate.ddl-auto
(Enum)是一个Hibernate特性,它以更细粒度的方式控制行为。本指南后面将更详细地介绍此功能。
9.2. Initialize a Database Using Hibernate
您可以显式设置spring.jpa.hibernate.ddl-auto
,标准的Hibernate属性值为None
、Valid
、update
、create
和Create-Drop
。Spring Boot根据它是否认为您的数据库是嵌入式的来为您选择一个缺省值。如果没有检测到模式管理器,则默认为Create-Drop
,否则默认为None
。通过查看连接
类型和JDBC url来检测嵌入式数据库。hsqldb
、h2
和derby
是候选代码,而其他代码不是。从内存中切换到“真实”数据库时要小心,不要对新平台中是否存在表和数据做出假设。您必须显式设置DDL-AUTO
,或者使用其他机制之一来初始化数据库。
You can output the schema creation by enabling the org.hibernate.SQL logger. This is done for you automatically if you enable the debug mode. |
此外,如果Hibernate从头开始创建模式(也就是,如果DDL-AUTO
属性设置为CREATE
或CREATE-DROP
),则类路径根目录中名为port.sql
的文件将在启动时执行。如果您仔细的话,这对于演示和测试可能很有用,但您可能不希望出现在生产中的类路径上。它是一种休眠特性(与Spring无关)。
9.3. Initialize a Database Using Basic SQL Scripts
Spring Boot可以自动创建JDBCDataSource
或R2DBCConnectionFactory
的模式(DDL脚本)并对其进行初始化(DML脚本)。它从标准的根类路径位置加载SQL:schema.sql
和data.sql
。此外,Spring Boot还处理架构-${Platform}.SQL
和data-${Platform}.SQL
文件(如果存在),其中Platform
是spring.sql.init.Platform
的值。这允许您在必要时切换到特定于数据库的脚本。例如,您可以选择将其设置为数据库的供应商名称(hsqldb
、h2
、Oracle
、MySQL
、PostgreSQL
等)。默认情况下,仅在使用嵌入式内存数据库时才执行SQL数据库初始化。要始终初始化SQL数据库,而不考虑其类型,请将spring.sql.init.mode
设置为Always
。同样,要禁用初始化,请将spring.sql.init.mode
设置为Never
。默认情况下,Spring Boot启用其基于脚本的数据库初始化器的快速故障特性。这意味着,如果脚本导致异常,应用程序将无法启动。您可以通过设置spring.sql.init.continue-on-error
.来调整该行为
默认情况下,基于脚本的DataSource
初始化在创建任何JPAEntityManagerFactory
Bean之前执行。schema.sql
可以用来为JPA管理的实体创建模式,data.sql
可以用来填充它。虽然我们不建议使用多种数据源初始化技术,但如果您希望基于脚本的<代码>数据源
初始化能够在Hibernate执行的架构创建的基础上构建,请将spring.jpa.defer-datasource-initialization
设置为<代码>真
。这将推迟数据源初始化,直到创建并初始化任何EntityManagerFactory
Bean之后。然后,可以使用schema.sql
向Hibernate执行的任何模式创建添加内容,并且data.sql
可以用来填充它。
如果您使用的是更高级的数据库迁移工具,如Flyway或Liquibase,则应该单独使用它们来创建和初始化模式。不建议在Flyway或Liquibase中使用基本的schema.sql
和data.sql
脚本,并且在未来的版本中将不再支持。
9.4. Initialize a Spring Batch Database
如果您使用的是Spring Batch,那么它预装了适用于大多数流行数据库平台的SQL初始化脚本。Spring Boot可以检测您的数据库类型并在启动时执行这些脚本。如果使用嵌入式数据库,则默认情况下会发生这种情况。您还可以为任何数据库类型启用它,如下例所示:
spring.batch.jdbc.initialize-schema=always
您还可以通过将spring.batch.jdbc.initialize-schema
设置为Never显式关闭初始化。
9.5. Use a Higher-level Database Migration Tool
9.5.1. Execute Flyway Database Migrations on Startup
要在启动时自动运行Flyway数据库迁移,请将org.flywaydb:flyway-core
添加到类路径中。
通常,迁移是V<;VERSION>;__<;NAME>;.sql
形式的脚本(使用<代码><;版本&>
一个下划线分隔的版本,如‘1’或‘2_1’)。默认情况下,它们位于名为classpath:db/Migration
的目录中,但您可以通过设置spring.flyway.Locations
来修改该位置。这是一个或多个类路径:
或文件系统:
位置的逗号分隔列表。例如,以下配置将在默认类路径位置和/opt/Migration
目录中搜索脚本:
spring.flyway.locations=classpath:db/migration,filesystem:/opt/migration
您还可以添加特殊的{供应商}
占位符以使用供应商特定的脚本。假设以下情况:
spring.flyway.locations=classpath:db/migration/{vendor}
上面的配置没有使用db/Migration
,而是根据数据库的类型设置要使用的目录(例如db/Migration/MySQL
用于MySQL)。支持的数据库列表位于DatabaseDriver
中。
迁移也可以用Java编写。Flyway将使用实现JavaMigration
的任何Bean自动配置。
Flyway Properties
提供了Flyway的大部分设置和一小部分可用于禁用迁移或关闭位置检查的附加属性。如果您需要对配置进行更多控制,请考虑注册Flyway ConfigurationCustomizer
Bean。
Spring Boot调用Flyway.Migrate()
来执行数据库迁移。如果您想要更多控制,请提供实现
FlywayMigrationStrategy
.>的<代码>@Bean
Flyway支持SQL和Java回调。要使用基于SQL的回调,请将回调脚本放在classpath:db/Migration
目录中。要使用基于Java的回调,请创建一个或多个实现回调
的Bean。任何此类Bean都会自动注册到Flyway
。可以使用@Order
或通过实现Ordered
对它们进行排序。也可以检测到实现已弃用的Flyway Callback
接口的Bean,但是它们不能与回调
Bean一起使用。
默认情况下,Flyway自动生成上下文中的(@Primary
)DataSource
,并将其用于迁移。如果您想使用不同的DataSource
,您可以创建一个,并将其@Bean
标记为@FlywayDataSource
。如果这样做并且需要两个数据源,请记住创建另一个数据源,并将其标记为@Primary
。或者,您也可以通过在外部属性中设置spring.flyway.[URL,User,Password]
来使用Flyway的原生DataSource
。设置spring.flyway.url
或spring.flyway.user
足以使Flyway使用其自己的数据源
。如果尚未设置这三个属性中的任何一个,则将使用其等效的spring.datource
属性的值。
您还可以使用Flyway为特定场景提供数据。例如,您可以将特定于测试的迁移放在src/test/resource
中,并且它们仅在您的应用程序启动测试时运行。此外,您还可以使用特定于配置文件的配置来自定义spring.flyway.Locations
,以便某些迁移仅在特定配置文件处于活动状态时运行。例如,在application-dev.properties
中,您可以指定以下设置:
spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration
通过该设置,dev/db/Migration
中的迁移仅在dev
配置文件处于活动状态时运行。
9.5.2. Execute Liquibase Database Migrations on Startup
要在启动时自动运行Liquibase数据库迁移,请将org.iquibase:iquibase-core
添加到类路径中。
当您向类路径添加 |
默认情况下,主更改日志是从db/changelog/db.changelog-master.yaml
,读取的,但是您可以通过设置spring.iquibase.change-log
来更改位置。除了YAML之外,Liquibase还支持JSON、XML和SQL更改日志格式。
默认情况下,Liquibase自动生成上下文中的(@Primary
)DataSource
,并将其用于迁移。如果您需要使用不同的数据源
,您可以创建一个,并将其@Bean
标记为@Liquibase DataSource
。如果这样做并且需要两个数据源,请记住创建另一个数据源,并将其标记为@Primary
。或者,您也可以使用Liquibase的原生DataSource
,方法是在外部属性中设置spring.iquibase.[DRIVER-CLASS-NAME,URL,USER,PASSWORD]
。设置spring.iquibase.url
或spring.iqubase.user
足以使Liquibase使用其自己的DataSource
。如果尚未设置这三个属性中的任何一个,则将使用其等效的spring.datource
属性的值。
有关上下文、默认模式等可用设置的详细信息,请参阅Liquibase Properties
。
9.6. Depend Upon an Initialized Database
数据库初始化是在应用程序作为应用程序上下文刷新的一部分启动时执行的。为了允许在启动期间访问已初始化的数据库,将自动检测充当数据库初始化器的Bean和需要初始化该数据库的Bean。其初始化依赖于已被初始化的数据库的Bean被配置为依赖于初始化它的那些Bean。如果在启动期间,您的应用程序尝试访问数据库,但数据库尚未初始化,则可以配置对初始化数据库并要求数据库已初始化的Bean的其他检测。
9.6.1. Detect a Database Initializer
Spring Boot将自动检测初始化SQL数据库的以下类型的Bean:
-
DataSourceScriptDatabaseInitializer
-
实体管理器工厂
-
Flyway
-
Flyway MigrationInitializer
-
R2dbcScriptDatabaseInitializer
-
SpringLiquibase
如果您正在使用数据库初始化库的第三方启动器,它可能会提供一个检测器,以便也自动检测其他类型的Bean。要检测其他Bean,请在META-INF/spring.Factory
中注册DatabaseInitializerDetector
的实现。
9.6.2. Detect a Bean That Depends On Database Initialization
Spring Boot将根据数据库初始化自动检测以下类型的Bean:
-
<代码>抽象实体管理器工厂Bean (除非
spring.jpa.defer-datasource-initialization
设置为<代码>真 ) -
DSLContext
(JOOQ) -
<代码>实体管理器工厂 (除非
spring.jpa.defer-datasource-initialization
设置为<代码>真 ) -
JdbcOperations
-
命名参数JdbcOperations
如果您使用的是第三方启动器数据访问库,它可能会提供一个检测器,以便也自动检测其他类型的Bean。要检测其他Bean,请在<代码>META-INF/spring.Factory
DependsOnDatabaseInitializationDetector>中注册一个Bean实现。或者,使用@DependsOnDatabaseInitialization
.注释Bean的类或其<代码>@Bean
方法
10. Messaging
Spring Boot提供了许多启动器来支持消息传递。本节回答了在Spring Boot中使用消息传递时出现的问题。
10.1. Disable Transacted JMS Session
如果您的JMS Broker不支持事务会话,则必须完全禁用对事务的支持。如果您创建了自己的JmsListenerContainerFactory
,则无需执行任何操作,因为默认情况下不能对其进行事务处理。如果您想使用DefaultJmsListenerContainerFactoryConfigurer
来重用Spring Boot的缺省设置,您可以禁用事务处理会话,如下所示:
@Configuration(proxyBeanMethods = false) public class MyJmsConfiguration { @Bean public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) { DefaultJmsListenerContainerFactory listenerFactory = new DefaultJmsListenerContainerFactory(); configurer.configure(listenerFactory, connectionFactory); listenerFactory.setTransactionManager(null); listenerFactory.setSessionTransacted(false); return listenerFactory; } }
上面的示例重写默认工厂,并且它应该应用于您的应用程序定义的任何其他工厂(如果有)。
11. Batch Applications
当人们在Spring Boot应用程序中使用Spring Batch时,经常会出现许多问题。本节将讨论这些问题。
11.1. Specifying a Batch Data Source
默认情况下,批处理应用程序需要数据源
来存储作业详细信息。默认情况下,Spring Batch需要单个DataSource
。若要使其使用应用程序主DataSource
以外的DataSource
,请声明一个DataSource
Bean,并使用@BatchDataSource
注释其@Bean
方法。如果这样做并且需要两个数据源,请记住将另一个@Primary
标记为。若要获得更好的控制,请实现BatchConfigurer
。详见the Javadoc of@EnableBatchProcessing
。
有关Spring Batch的更多信息,请参见Spring Batch项目页面。
11.2. Running Spring Batch Jobs on Startup
通过将@EnableBatchProcessing
添加到您的一个@Configuration
类中,可以启用Spring Batch自动配置。
如果在应用程序上下文中找到单个
JobLauncherApplicationRunner
>作业
,则在启动时执行该作业(有关详细信息,请参阅
spring.Batch.job.name指定应该执行的作业。
若要禁止运行在应用程序内容中找到的作业
,请将spring.Batch.job.Enabled
设置为False。
11.3. Running From the Command Line
Spring Boot将任何以--
开头的命令行参数转换为要添加到环境
的属性,请参阅访问命令行属性。这不应用于将参数传递给批处理作业。要在命令行上指定批处理参数,请使用常规格式(即不带--
),如下例所示:
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue
如果在命令行上指定Environment
的属性,作业将忽略该属性。请考虑以下命令:
$ java -jar myapp.jar --server.port=7070 someParameter=someValue
这只为批处理作业提供了一个参数:ome参数=omeValue
。
11.4. Storing the Job Repository
Spring Batch需要作业
存储库的数据存储。如果您使用的是Spring Boot,则必须使用实际的数据库。注意,它可以是内存中的数据库,请参阅配置作业存储库。
12. Actuator
Spring Boot包括Spring Boot执行器。本节回答了在使用它时经常出现的问题。
12.1. Change the HTTP Port or Address of the Actuator Endpoints
在独立应用程序中,Actuator HTTP端口默认为与主HTTP端口相同。要使应用程序侦听不同的端口,请设置外部属性:Management.server.port
。要侦听完全不同的网络地址(例如,当您有一个用于管理的内部网络和一个用于用户应用程序的外部网络时),您还可以将Management.server.Address
设置为服务器能够绑定到的有效IP地址。
有关更多详细信息,请参阅“生产就绪特性”一节中的ManagementServerProperties
源代码和actuator.html。
12.2. Customize the ‘whitelabel’ Error Page
如果您遇到服务器错误(使用JSON和其他媒体类型的机器客户端应该会看到带有正确错误代码的合理响应),Spring Boot会安装一个‘White Label’错误页面,您可以在浏览器客户端看到该页面。
Set server.error.whitelabel.enabled=false to switch the default error page off. Doing so restores the default of the servlet container that you are using. Note that Spring Boot still tries to resolve the error view, so you should probably add your own error page rather than disabling it completely. |
用您自己的错误页面覆盖错误页面取决于您使用的模板技术。例如,如果您使用Thymeleaf,则可以添加error.html
模板。如果使用的是FreeMarker,则可以添加error.ftlh
模板。通常,您需要使用名称Error
解析的View
或处理/Error
路径的@控制器
。除非您替换了一些默认配置,否则您应该在ApplicationContext
中找到BeanNameViewResolver
,因此名为Error
的@Bean
就是这样做的一种方法。有关更多选项,请参阅ErrorMvcAutoConfiguration
。
有关如何在Servlet容器中注册处理程序的详细信息,请参阅“错误处理一节。
12.3. Sanitize Sensitive Values
/env
、/configprops
和/Quartz
端点返回的信息可能有些敏感。默认情况下,所有值都经过清理(替换为*
)。可以使用该终结点的showValues
属性为每个终结点配置查看未清理表单中的原始值。此属性可以配置为具有下列值:
-
始终
-所有值都以未经清理的形式显示给所有用户 -
Never-始终清理所有值(替换为`++
) -
WHEN_AUTHORIZED
-所有值都以未经清理的形式显示给授权用户
对于HTTP终结点,如果用户已通过身份验证并具有由终结点的Roles属性配置的角色,则认为该用户已获得授权。默认情况下,任何经过身份验证的用户都是经过授权的。对于JMX端点,所有用户始终获得授权。
management.endpoint.env.show-values=WHEN_AUTHORIZED
management.endpoint.env.roles=admin
上面的配置使具有admin
角色的所有用户能够从/env
终结点以其原始形式查看所有值。
When show-values is set to ALWAYS or WHEN_AUTHORIZED any sanitization applied by a SanitizingFunction will still be applied. |
12.4. Map Health Indicators to Micrometer Metrics
Spring Boot运行状况指示器返回状态
类型以指示整体系统运行状况。如果您想要监视或警告特定应用程序的运行状况级别,您可以将这些状态导出为带有测微计的指标。默认情况下,Spring Boot使用状态码UP、DOWN、OUT_OF_SERVICE和UNKNOWN。要导出这些状态,您需要将这些状态转换为一组数字,以便它们可以与微米量规
一起使用。
下面的示例显示了编写此类导出器的一种方法:
@Configuration(proxyBeanMethods = false) public class MyHealthMetricsExportConfiguration { public MyHealthMetricsExportConfiguration(MeterRegistry registry, HealthEndpoint healthEndpoint) { // This example presumes common tags (such as the app) are applied elsewhere Gauge.builder("health", healthEndpoint, this::getStatusCode).strongReference(true).register(registry); } private int getStatusCode(HealthEndpoint health) { Status status = health.health().getStatus(); if (Status.UP.equals(status)) { return 3; } if (Status.OUT_OF_SERVICE.equals(status)) { return 2; } if (Status.DOWN.equals(status)) { return 1; } return 0; } }
13. Security
本节讨论在使用Spring Boot时有关安全性的问题,包括在Spring Boot中使用Spring Security时出现的问题。
有关Spring Security的更多信息,请参阅Spring Security项目页面。
13.1. Switch off the Spring Boot Security Configuration
如果在应用程序中使用SecurityFilterChain
Bean定义@configuration
,它将关闭Spring Boot中的默认WebApp安全设置。
13.2. Change the UserDetailsService and Add User Accounts
如果您提供AuthenticationManager
、AuthenticationProvider
或UserDetailsService
类型的@Bean
,则不会为InMemory yUserDetailsManager
创建默认的@Bean
。这意味着您拥有Spring Security的全部功能集(例如各种身份验证选项)。
添加用户帐户的最简单方法是提供您自己的UserDetailsService
Bean。
13.3. Enable HTTPS When Running behind a Proxy Server
确保您的所有主端点只能通过HTTPS使用,这对于任何应用程序都是一项重要的工作。如果您使用Tomcat作为Servlet容器,那么Spring Boot会在检测到某些环境设置时自动添加Tomcat自己的RemoteIpValve
,并且您应该能够依赖HttpServletRequest
来报告它是否安全(甚至在处理真正的SSL终止的代理服务器的下游)。标准行为由某些请求头(x-Forwarded-For
和x-Forwarded-proto
)的存在或不存在决定,它们的名称是常规的,因此它应该适用于大多数前端代理。您可以通过向Applation.Properties
添加一些条目来打开阀门,如下例所示:
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
(如果存在这两种属性中的任何一种,则开启阀门。或者,您可以通过使用WebServerFactoryCustomizer
Bean自定义TomcatServletWebServerFactory
来添加RemoteIpValve
。)
要将Spring Security配置为要求对所有(或某些)请求使用安全通道,请考虑添加您自己的SecurityFilterChain
Bean,该Bean添加以下HttpSecurity
配置:
@Configuration public class MySecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // Customize the application security ... http.requiresChannel((channel) -> channel.anyRequest().requiresSecure()); return http.build(); } }
14. Hot Swapping
Spring Boot支持热插拔。本节回答有关其工作原理的问题。
14.1. Reload Static Content
有几个选项可用于热重新加载。推荐的方法是使用spring-boot-devtools
,,因为它提供了额外的开发时特性,例如支持快速应用程序重启和LiveReload,以及合理的开发时配置(如模板缓存)。DevTools通过监视类路径的更改来工作。这意味着必须“构建”静态资源更改才能使更改生效。默认情况下,当您保存更改时,这会在Eclipse中自动发生。在IntelliJ Idea中,Make Project命令触发必要的构建。由于默认重新启动排除,对静态资源的更改不会触发应用程序重新启动。然而,它们确实会触发实时重新加载。
或者,在IDE中运行(尤其是在启动调试的情况下)是进行开发的好方法(所有现代的IDE都允许重新加载静态资源,并且通常也允许对Java类更改进行热插拔)。
最后,可以配置Maven和Gradle插件(参见addResources
属性),以支持从命令行运行,并直接从源重新加载静态文件。如果您使用高级工具编写代码,则可以将其与外部css/js编译器进程一起使用。
14.2. Reload Templates without Restarting the Container
Spring Boot支持的大多数模板技术都包含一个禁用缓存的配置选项(本文稍后将对此进行介绍)。如果您使用Spring-ot-DevTools
模块,这些属性将在开发时自动配置。
14.2.1. Thymeleaf Templates
如果您使用Thymeleaf,请将spring.thoreleaf.cache
设置为FALSE
。有关其他胸腺叶自定义选项,请参阅ThymeleafAutoConfiguration
。
14.2.2. FreeMarker Templates
如果使用FreeMarker,请将spring.freemarker.cache
设置为FALSE
。有关其他自由标记定制选项,请参阅FreeMarkerAutoConfiguration
。
14.3. Fast Application Restarts
Spring-Boot-DevTools
模块包括对应用程序自动重启的支持。虽然没有JRebel这样的技术快,但它通常比“冷启动”快得多。在研究本文后面讨论的一些更复杂的重载选项之前,您可能应该先试一试。
有关更多详细信息,请参阅using.html部分。
15. Testing
Spring Boot包括许多测试实用程序和支持类,以及提供常见测试依赖项的专用启动器。本节回答有关测试的常见问题。
15.1. Testing With Spring Security
Spring Security支持以特定用户身份运行测试。例如,下面代码片断中的测试将以具有admin
角色的经过身份验证的用户运行。
@WebMvcTest(UserController.class) class MySecurityTests { @Autowired private MockMvc mvc; @Test @WithMockUser(roles = "ADMIN") void requestProtectedUrlWithUser() throws Exception { this.mvc.perform(get("/")); } }
Spring Security提供了与Spring MVC测试的全面集成,在使用@WebMvcTest
切片和MockMvc
测试控制器时也可以使用。
有关Spring Security测试支持的更多详细信息,请参阅Spring Security的参考文档。
15.2. Use Testcontainers for Integration Testing
Testtainers库提供了一种管理在Docker容器内运行的服务的方法。它与JUnit集成,允许您编写一个测试类,该类可以在任何测试运行之前启动容器。Testtainers对于编写与真正的后端服务(如MySQL、MongoDB、Cassandra等)对话的集成测试特别有用。在Spring Boot测试中可以使用TestContainers,如下所示:
@SpringBootTest @Testcontainers class MyIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.2"); @Test void myTest() { // ... } }
这将在运行任何测试之前启动运行Neo4j的停靠容器(如果Docker在本地运行)。在大多数情况下,您需要使用运行容器的详细信息来配置应用程序,例如容器IP或端口。
这可以通过静态@DynamicPropertySource
方法来完成,该方法允许将动态属性值添加到Spring Environment。
@SpringBootTest @Testcontainers class MyIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.2"); @Test void myTest() { // ... } @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } }
上面的配置允许应用程序中与Neo4j相关的Bean与运行在Testtainers管理的Docker容器中的Neo4j通信。
15.3. Structure @Configuration
classes for inclusion in slice tests
切片测试的工作原理是将Spring框架的组件扫描限制为基于组件类型的有限组件集。对于任何不是通过组件扫描创建的Bean,例如,使用@Bean
注释创建的Bean,切片测试将无法在应用程序上下文中包括/排除它们。请考虑以下示例:
@Configuration(proxyBeanMethods = false) public class MyConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()); return http.build(); } @Bean @ConfigurationProperties("app.datasource.second") public BasicDataSource secondDataSource() { return DataSourceBuilder.create().type(BasicDataSource.class).build(); } }
对于具有上述@Configuration
类的应用程序的@WebMvcTest
,您可能希望在应用程序上下文中有SecurityFilterChain
Bean,这样您就可以测试您的控制器端点是否得到了适当的保护。但是,@WebMvcTest的组件扫描筛选器不会拾取MyConfiguration
,因为它与筛选器指定的任何类型都不匹配。您可以通过使用@Import(MyConfiguration.class)
注释测试类来显式地包含配置。这将加载MyConfiguration
中的所有Bean,包括测试Web层时不需要的BasicDataSource
Bean。将配置类一分为二将允许仅导入安全配置。
@Configuration(proxyBeanMethods = false) public class MySecurityConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()); return http.build(); } }
@Configuration(proxyBeanMethods = false) public class MyDatasourceConfiguration { @Bean @ConfigurationProperties("app.datasource.second") public BasicDataSource secondDataSource() { return DataSourceBuilder.create().type(BasicDataSource.class).build(); } }
当需要在片测试中包括特定域的Bean时,使用单个配置类可能效率低下。相反,将应用程序的配置结构化为具有特定域的Bean的多个粒度类,可以仅为特定的切片测试导入它们。
16. Build
Spring Boot包括Maven和Gradle的构建插件。本节回答有关这些插件的常见问题。
16.1. Generate Build Information
Maven插件和Gradle插件都允许生成包含项目坐标、名称和版本的构建信息。还可以配置插件以通过配置添加其他属性。当存在这样的文件时,Spring Boot会自动配置BuildProperties
Bean。
要使用Maven生成构建信息,请添加对Build-Info
目标的执行,如下例所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See the Spring Boot Maven Plugin documentation for more details. |
下面的示例对Gradle执行相同的操作:
springBoot { buildInfo() }
See the Spring Boot Gradle Plugin documentation for more details. |
16.2. Generate Git Information
Maven和Gradle都允许生成一个git.properties
文件,其中包含项目构建时git
源代码存储库的状态信息。
对于Maven用户,SpringBoot-starter-Parent
POM包括一个预配置的插件,用于生成git.properties
文件。要使用它,请将以下Git Commit ID插件
声明添加到您的POM中:
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Gradle用户使用gradle-git-properties
插件也可以达到同样的效果,如下例所示:
plugins {
id "com.gorylenko.gradle-git-properties" version "2.3.2"
}
Maven和Gradle插件都允许配置git.properties
中包含的属性。
The commit time in git.properties is expected to match the following format: yyyy-MM-dd’T’HH:mm:ssZ . This is the default format for both plugins listed above. Using this format lets the time be parsed into a Date and its format, when serialized to JSON, to be controlled by Jackson’s date serialization configuration settings. |
16.3. Customize Dependency Versions
SpringBoot-Dependents
POM管理常见依赖项的版本。Maven和Gradle的Spring Boot插件允许使用构建属性定制这些托管依赖项版本。
Each Spring Boot release is designed and tested against this specific set of third-party dependencies. Overriding versions may cause compatibility issues. |
要用Maven覆盖依赖项版本,请参阅Maven插件文档的本节。
要覆盖Gradle中的依赖项版本,请参阅Gradle插件文档的这一节。
16.4. Create an Executable JAR with Maven
SpringBoot-maven-plugin
可用于创建可执行的“胖”JAR。如果您使用Spring-Boot-starter-Parent
POM,您可以声明插件,并按如下方式重新打包您的JAR:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果您不使用父POM,您仍然可以使用该插件。但是,您还必须添加一个<;Executions>;
部分,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{spring-boot-version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
有关完整用法详细信息,请参阅插件文档。
16.5. Use a Spring Boot Application as a Dependency
与WAR文件一样,Spring Boot应用程序并不打算用作依赖项。如果您的应用程序包含要与其他项目共享的类,建议的方法是将该代码移到单独的模块中。然后,您的应用程序和其他项目可以依赖于单独的模块。
如果您无法按照上面的建议重新排列代码,则必须配置Spring Boot的Maven和Gradle插件以生成适合用作依赖项的单独构件。可执行归档文件不能用作依赖项,因为可执行JAR格式将应用程序类打包在Boot-INF/Classes
中。这意味着当可执行JAR用作依赖项时,无法找到它们。
要生成两个构件,一个可用作依赖项,另一个可执行,必须指定分类器。此分类器应用于可执行档案的名称,保留默认档案作为依赖项使用。
要在Maven中配置exec
的分类器,可以使用以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
16.6. Extract Specific Libraries When an Executable Jar Runs
可执行JAR中的大多数嵌套库不需要解压缩即可运行。但是,某些库可能会出现问题。例如,JRuby包括它自己的嵌套JAR支持,这假设jruby-plee.jar
始终作为文件本身直接可用。
要处理任何有问题的库,您可以标记在可执行JAR第一次运行时应该自动解压特定的嵌套JAR。此类嵌套JAR被写入由java.io.tmpdir
系统属性标识的临时目录下。
Care should be taken to ensure that your operating system is configured so that it will not delete the jars that have been unpacked to the temporary directory while the application is still running. |
例如,要指示应该使用Maven插件将JRuby标记为解包,您需要添加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
16.7. Create a Non-executable JAR with Exclusions
通常,如果您将一个可执行文件和一个非可执行文件JAR作为两个单独的构建产品,则可执行文件版本具有库JAR中不需要的附加配置文件。例如,可以从非可执行JAR中排除Applation.yml
配置文件。
在Maven中,可执行JAR必须是主要构件,您可以为库添加一个分类的JAR,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
16.8. Remote Debug a Spring Boot Application Started with Maven
要将远程调试器附加到使用Maven启动的Spring Boot应用程序,可以使用Maven插件的jvmArguments
属性。
有关详细信息,请参阅此示例。
16.9. Build an Executable Archive From Ant without Using spring-boot-antlib
要使用Ant构建,您需要获取依赖项、编译,然后创建一个JAR或WAR归档。要使其可执行,您可以使用SpringBoot-antlib
模块,也可以按照以下说明操作:
-
如果您正在构建JAR,请将应用程序的类和资源打包到嵌套的
引导-INF/CLASSES
目录中。如果您正在构建WAR,请像往常一样将应用程序的类打包到嵌套的WEB-INF/CLASSES
目录中。 -
将运行时依赖项添加到嵌套的
Boot-INF/lib
目录(对于JAR)或WEB-INF/lib
目录(对于WAR)。记住Not压缩存档中的条目。 -
将
提供的
(嵌入式容器)依赖项添加到嵌套的Boot-INF/lib
目录中(对于JAR)或WEB-INF/lib提供的
目录(对于WAR)。记住Not压缩存档中的条目。 -
在归档文件的根目录下添加
SpringBoot-Loader
类(这样main-Class
就可用了)。 -
使用适当的启动器(如JAR文件的
JarLauncher
)作为清单中的main-Class
属性,并主要通过设置Start-Class
属性将它需要的其他属性指定为清单条目 - 。
以下示例显示如何使用Ant构建可执行归档文件:
<target name="build" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
17. Traditional Deployment
Spring Boot支持传统部署以及更现代的部署形式。本节回答有关传统部署的常见问题。
17.1. Create a Deployable War File
Because Spring WebFlux does not strictly depend on the servlet API and applications are deployed by default on an embedded Reactor Netty server, War deployment is not supported for WebFlux applications. |
生成可部署的WAR文件的第一步是提供SpringBootServletInitializer
子类并覆盖其配置
方法。这样做可以利用Spring框架的Servlet 3.0支持,并允许您在Servlet容器启动应用程序时对其进行配置。通常,您应该更新应用程序的主类以扩展SpringBootServletInitializer
,如下面的示例所示:
@SpringBootApplication public class MyApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(MyApplication.class); } public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
下一步是更新构建配置,以便您的项目生成WAR文件而不是JAR文件。如果您使用Maven和SpringBoot-starter-parent
(它为您配置Maven的WAR插件),您所需要做的就是修改pom.xml
以将打包更改为WAR,如下所示:
<packaging>war</packaging>
如果您使用Gradle,则需要修改build.gradle
,将WAR插件应用到工程中,具体操作如下:
apply plugin: 'war'
该过程的最后一步是确保嵌入的Servlet容器不会干扰WAR文件所部署到的Servlet容器。为此,您需要将嵌入的Servlet容器依赖项标记为已提供。
如果使用Maven,下面的示例将Servlet容器(在本例中为Tomcat)标记为已提供:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
如果使用Gradle,下面的示例将Servlet容器(在本例中为Tomcat)标记为已提供:
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
// ...
}
providedRuntime is preferred to Gradle’s compileOnly configuration. Among other limitations, compileOnly dependencies are not on the test classpath, so any web-based integration tests fail. |
如果您使用Spring Boot构建工具,将嵌入的Servlet容器依赖项标记为提供会生成一个可执行的WAR文件,其中提供的依赖项打包在lib提供的
目录中。这意味着,除了可以部署到Servlet容器之外,您还可以通过在命令行上使用Java-jar
来运行应用程序。
17.2. Convert an Existing Application to Spring Boot
要将现有的非Web Spring应用程序转换为Spring Boot应用程序,请替换创建ApplicationContext
的代码,并将其替换为对SpringApplicationBuilder
或SpringApplicationBuilder
的调用。Spring MVC Web应用程序通常可以先创建可部署的WAR应用程序,然后再将其迁移到可执行的WAR或JAR。请参阅入门指南,了解如何将JAR转换为WAR。
要通过扩展SpringBootServletInitializer
(例如,在名为Application
的类中)并添加Spring Boot@SpringBootApplication
注释来创建可部署的WAR,请使用如下例所示的代码:
@SpringBootApplication public class MyApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // Customize the application or call application.sources(...) to add sources // Since our example is itself a @Configuration class (via @SpringBootApplication) // we actually do not need to override this method. return application; } }
请记住,您放在源代码
中的任何内容都只是一个SpringApplicationContext
。正常情况下,任何已经起作用的东西都应该在这里起作用。可能有一些Bean可以在以后删除,并让Spring Boot为它们提供自己的缺省值,但在您需要这样做之前,应该可以让一些东西运行起来。
静态资源可以移到类路径根目录中的/public
(或/静态
或/resource
或/META-INF/resource
)。这同样适用于Messages.Properties
(Spring Boot会在类路径的根目录中自动检测到它)。
简单地使用SpringDispatcherServlet
和Spring Security应该不需要进一步的更改。如果您的应用程序中有其他功能(例如,使用其他Servlet或筛选器),则可能需要向应用程序
上下文添加一些配置,方法是替换web.xml
中的那些元素,如下所示:
-
Servlet
或ServletRegistrationBean
类型的@Bean
将该Bean安装在容器中,就像它是web.xml
中的Servlet/和;Servlet映射/
。 -
Filter
或FilterRegistrationBean
类型的@Bean
的行为类似(作为;筛选器/&>和
<;筛选器映射/
)。 -
可以通过
应用程序
中的@ImportResource
添加XML文件中的ApplicationContext
。或者,已经大量使用注释配置的情况可以在几行代码中重新创建为@Bean
定义。
WAR文件工作后,您可以通过向应用程序
添加一个main
方法使其可执行,如下例所示:
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
如果要将应用程序作为WAR或可执行应用程序启动,则需要在
Java
Kotlin
|
应用程序可以分为多个类别:
-
没有
web.xml
的Servlet 3.0+应用程序。 -
具有
web.xml
的应用程序。 -
具有上下文层次结构的应用程序。
-
没有上下文层次结构的应用程序。
所有这些都应该是可以翻译的,但每一种可能需要略有不同的技术。
如果Servlet 3.0+应用程序已经使用了Spring Servlet 3.0+初始化器支持类,那么它们可能很容易转换。通常,现有WebApplicationInitializer
中的所有代码都可以移到SpringBootServletInitializer
中。如果您的现有应用程序有多个ApplicationContext
(例如,如果它使用AbstractDispatcherServletInitializer
),则您可以将所有上下文源合并到单个SpringApplication
中。您可能会遇到的主要复杂情况是,如果组合不起作用,您需要维护上下文层次结构。有关示例,请参阅有关构建层次结构的条目。通常需要分解包含特定于Web的功能的现有父上下文,以便所有ServletContextAware
组件都在子上下文中。
还不是Spring应用程序的应用程序可能可以转换为Spring Boot应用程序,前面提到的指导可能会有所帮助。然而,你仍然可能会遇到问题。在这种情况下,我们建议在Stack Overflow上使用标记SpringBoot
提问。
17.3. Deploying a WAR to WebLogic
要将Spring Boot应用程序部署到WebLogic,您必须确保您的Servlet初始化器直接实现WebApplicationInitializer
(即使您从已经实现它的基类扩展)。
WebLogic的典型初始值设定项应类似于以下示例:
@SpringBootApplication public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer { }
如果您使用Logback,您还需要告诉WebLogic首选打包的版本,而不是服务器预装的版本。为此,您可以添加一个包含以下内容的WEB-INF/weblogic.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app https://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>