本节提供了一些常见的 ‘how do I do that…’ 的问题的答案,这些问题在使用 Spring Boot 时经常出现。它的覆盖面不是详尽无遗的,但它涵盖了很多。
如果你有一个特定的问题,我们这里没有介绍,你可能希望查看 stackoverflow.com,看看是否有人已经提供了答案。这也是一个询问新问题的好地方(请使用 我们也很乐意延长这一部分。如果你想添加一个 ‘how-to’,请向我们发送一个推送请求。 本节包含直接与 Spring Boot 应用程序相关的主题。
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
Spring Boot 自动配置尽力做正确的事情,但有时事情会失败,并且很难解释原因。
在任何 Spring Boot 通过查看源代码和 Javadoc 可以回答更多的问题。当阅读代码时,记住以下的经验法则:
在使用 org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
这个实现可以加载任意文件并将它们添加到 public class EnvironmentPostProcessorExample 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) { if (!path.exists()) { throw new IllegalArgumentException("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); } } }
可以使用
并非所有的 Spring 应用程序都必须是 web 应用程序(或 web 服务)。如果你想在 本节包括有关设置和读取属性和配置设置以及它们与 Spring Boot 应用程序的交互的主题。 与其在项目的构建配置中硬编码指定的一些属性,不如使用现有的构建配置自动扩展它们。这在 Maven 和 Gradle 中都是可能的。
可以通过使用资源筛选来自动扩展 Maven 项目中的属性。如果使用 app.encoding=@project.build.sourceEncoding@ app.java.version=@java.version@
如果不使用启动器父级,则需要在 <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
你还需要在 <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>
你可以通过配置 Java 插件的 processResources { expand(project.properties) } 然后,可以使用占位符引用你的 Gradle 项目的属性,如下面的示例所示: app.name=${name} app.description=${description}
spring.main.web-application-type=none spring.main.banner-mode=off 然后在启动时不打印 Spring Boot 横幅,应用程序不启动嵌入式 Web 服务器。
外部配置中定义的属性重写了用 Java API 指定的值,除了用于创建 new SpringApplicationBuilder() .bannerMode(Banner.Mode.OFF) .sources(demo.MyApp.class) .run(args); 现在考虑以下配置: spring.main.sources=com.acme.Config,com.acme.ExtraConfig spring.main.banner-mode=console
实际的应用程序现在显示横幅(通过配置覆盖),并使用
默认情况下,来自不同源的属性按照定义的顺序添加到 Spring
扩充和修改此排序的一个好方法是向应用程序源添加 还可以提供以下系统属性(或环境变量)来改变行为:
无论你在环境中设置什么,Spring Boot 总是加载
Spring Boot 记录在
更多详细内容请参阅
有些人喜欢使用(例如) server.port=${port:8080}
YAML 是一个 JSON 的超集,因此是用于以分层格式存储外部属性的简便语法,如下面的示例所示: spring: application: name: cruncher datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost/test server: port: 9000
创建一个名为
前面的示例 YAML 对应于以下 spring.application.name=cruncher spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost/test server.port=9000 有关 YAML 的更多信息请参阅 ‘Spring Boot 特性’ 部分中的 “小节 24.6, “使用 YAML 替代 Properties””。
Spring $ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
在 Spring Boot 中,还可以在 spring.profiles.active=production
这样设置的值由系统属性或环境变量设置代替,而不是由 更多详细信息请参阅 “Spring Boot 特性” 部分中的 “小节 25, 配置文件”。
YAML 文件实际上是由
如果 YAML 文档包含 server: port: 9000 --- spring: profiles: development server: port: 9001 --- spring: profiles: production server: port: 0 在前面的示例中,默认端口为 9000。然而,如果称为 ‘development’ 的 Spring 配置文件是活动的,那么端口是 9001。如果 ‘production’ 是激活的,那么端口是 0。
若要使用属性文件执行相同的操作,可以使用
Spring Boot 在运行时将
带有执行器特性的运行应用程序有一个
附录包含一个 每个 Spring Boot web 应用程序包含一个嵌入式 Web 服务器。这个特性导致了许多问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。本节回答了这些问题。 许多 Spring Boot 启动器包含默认嵌入式容器。
当切换到不同的 HTTP 服务器时,除了包含所需的依赖项之外,还需要排除默认依赖项。Spring Boot 为 HTTP 服务器提供独立的启动程序,以帮助尽可能容易地使该过程。 下面的 Maven 示例演示如何排除 Tomcat 并包含 Spring MVC 的 Jetty: <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>
下面的 Gradle 示例演示了如何排除 Netty 并包含 Spring WebFlux: configurations { // exclude Reactor Netty compile.exclude module: 'spring-boot-starter-reactor-netty' } dependencies { compile 'org.springframework.boot:spring-boot-starter-webflux' // Use Undertow instead compile 'org.springframework.boot:spring-boot-starter-undertow' // ... }
如果你的类路径包含启动 Web 服务器所需的位,Spring Boot 将自动启动它。若要禁用此行为,请在 spring.main.web-application-type=none
在独立应用程序中,主 HTTP 端口默认为
若要完全关闭 HTTP 节点,但仍要创建
更多详细信息,请参阅 ‘Spring Boot features’ 部分中的 “小节 27.4.4, “自定义嵌入式 Servlet 容器””,或
可以通过日志输出或
使用 @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) public class MyWebIntegrationTests { @Autowired ServletWebServerApplicationContext server; @LocalServerPort int port; // ... }
HTTP 响应压缩由 Jetty、Tomcat 和 Undertow支持。它可以在 server.compression.enabled=true
默认情况下,响应的长度必须至少为 2048 字节才进行压缩。可以通过设置 默认情况下,只有当内容类型是下列类型之一时,才对响应进行压缩:
可以通过设置
SSL 可以通过设置各种 server.port=8443 server.ssl.key-store=classpath:keystore.jks server.ssl.key-store-password=secret server.ssl.key-password=another-secret
有关所有支持的属性的详细信息请参阅
使用例如前面示例的配置意味着应用程序不再支持端口 8080 上的纯HTTP连接器。Spring Boot 不支持通过
你可以在 Spring Boot 应用程序中启用 HTTP/2 支持,使用
至于 Jetty 9.4.8,HTTP/2 也通过 Conscrypt library 被支持。为了实现这种支持,你的应用程序需要另外两个依赖项:
当使用 JDK 9 或更高版本时,Spring Boot 默认使用 Tomcat 9.0.x,它支持 HTTP/2 的开箱即用。或者,如果
库文件夹必须在 JVM 库路径中可用,如果还没有的话。你可以使用JVM参数,如 在没有本地支持的 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 支持开始。
通常,你应该首先考虑使用许多可用配置键中的一个,并通过在
前面的部分已经涵盖了许多常见的用例,例如压缩、SSL 或 HTTP/2。但是,如果配置的键不存在于你的用例中,那么你应该查看
下面的示例是针对 Tomcat 的 @Component public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { // customize the factory here } } 此外,Spring Boot 提供:
一旦你访问了
作为最后的手段,你也可以声明自己的
在 servlet 堆栈应用程序中,即使用
要使用 Spring bean 添加
在
与其它 Spring bean 一样,你可以定义 Servlet 过滤器 bean 的顺序;请确保查看“名为 “注册 Servlets、过滤器和监听器 为 Spring Beans” 的部分”。
如前面所述,任何 @Bean public FilterRegistrationBean registration(MyFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); return registration; } 可以通过它们各自的命名空间为 Tomcat、Undertow 和 Jetty 配置访问日志。 例如,以下设置使用自定义模式在 Tomcat 上进行日志访问。 server.tomcat.basedir=my-tomcat server.tomcat.accesslog.enabled=true server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
Undertow 的访问日志可以以类似的方式配置,如下面的示例所示: server.undertow.accesslog.enabled=true server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)
日志存储在 最后,Jetty 的访问日志也可以被配置如下: server.jetty.accesslog.enabled=true server.jetty.accesslog.filename=/var/log/jetty-access.log
默认情况下,日志被重定向到
你的应用程序可能需要发送
如果代理添加了传统的
如果使用 Tomcat,还可以配置用于携带转发信息的报头的名称,如下面的示例所示: server.tomcat.remote-ip-header=x-your-remote-ip-header server.tomcat.protocol-header=x-your-protocol-header
Tomcat 还配置有与要信任的内部代理相匹配的默认正则表达式。默认情况下, server.tomcat.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
通过关闭自动配置(为此,设置
你可以向 @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); tomcat.addAdditionalTomcatConnectors(createSslConnector()); return tomcat; } private Connector createSslConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler(); try { File keystore = new ClassPathResource("keystore").getFile(); File truststore = new ClassPathResource("keystore").getFile(); connector.setScheme("https"); connector.setSecure(true); connector.setPort(8443); protocol.setSSLEnabled(true); protocol.setKeystoreFile(keystore.getAbsolutePath()); protocol.setKeystorePass("changeit"); protocol.setTruststoreFile(truststore.getAbsolutePath()); protocol.setTruststorePass("changeit"); protocol.setKeyAlias("apitester"); return connector; } catch (IOException ex) { throw new IllegalStateException("can't access keystore: [" + "keystore" + "] or truststore: [" + "keystore" + "]", ex); } } 默认情况下,Spring Boot 使用的嵌入式 Tomcat 不支持 Cookie 格式的 "Version 0",因此你可能会看到以下错误: java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
如果可能的话,你应该考虑更新代码,只存储符合以后 Cookie 规范的值。但是,如果不能更改 Cookie 的写入方式,你可以使用 @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() { return (factory) -> factory.addContextCustomizers( (context) -> context.setCookieProcessor(new LegacyCookieProcessor())); }
向 @Bean public UndertowServletWebServerFactory servletWebServerFactory() { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override public void customize(Builder builder) { builder.addHttpListener(8080, "0.0.0.0"); } }); return factory; }
如果要在使用嵌入式容器的 Spring Boot 应用程序中使用 @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }
前面示例中所示的 bean 将任何 |