diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc index c76679e86c..e521ae0d61 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc @@ -581,7 +581,7 @@ We recommend using `application.properties` to configure HTTPS, as the HTTP conn [[howto-configure-http2]] === Configure HTTP/2 You can enable HTTP/2 support in your Spring Boot application with the configprop:server.http2.enabled[] configuration property. -This support depends on the chosen web server and the application environment, since that protocol is not supported out-of-the-box by JDK8. +This support depends on the chosen web server and the application environment, since that protocol is not supported out-of-the-box by all JDK8 releases. [NOTE] ==== @@ -599,8 +599,12 @@ As of Undertow 1.4.0+, HTTP/2 is supported without any additional requirement on [[howto-configure-http2-jetty]] ==== HTTP/2 with Jetty -As of Jetty 9.4.8, HTTP/2 is also supported with the https://www.conscrypt.org/[Conscrypt library]. -To enable that support, your application needs to have two additional dependencies: `org.eclipse.jetty:jetty-alpn-conscrypt-server` and `org.eclipse.jetty.http2:http2-server`. +For HTTP/2 support, Jetty requires the additional `org.eclipse.jetty.http2:http2-server` dependency. +Now depending on your deployment, you also need to choose other dependencies: + +* `org.eclipse.jetty:jetty-alpn-java-server` for applications running on JDK9+ +* `org.eclipse.jetty:jetty-alpn-openjdk8-server` for applications running on JDK8u252+ +* `org.eclipse.jetty:jetty-alpn-conscrypt-server` and the https://www.conscrypt.org/[Conscrypt library] with no JDK requirement diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/SslServerCustomizer.java index 666021b657..9d02b64cea 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/SslServerCustomizer.java @@ -96,10 +96,10 @@ class SslServerCustomizer implements JettyServerCustomizer { if (this.http2 == null || !this.http2.isEnabled()) { return createHttp11ServerConnector(server, config, sslContextFactory); } - Assert.state(isAlpnPresent(), - () -> "The 'org.eclipse.jetty:jetty-alpn-server' dependency is required for HTTP/2 support."); - Assert.state(isConscryptPresent(), () -> "The 'org.eclipse.jetty.http2:http2-server' and Conscrypt " - + "dependencies are required for HTTP/2 support."); + Assert.state(isJettyAlpnPresent(), + () -> "An 'org.eclipse.jetty:jetty-alpn-*-server' dependency is required for HTTP/2 support."); + Assert.state(isJettyHttp2Present(), + () -> "The 'org.eclipse.jetty.http2:http2-server' dependency is required for HTTP/2 support."); return createHttp2ServerConnector(server, config, sslContextFactory); } @@ -112,23 +112,40 @@ class SslServerCustomizer implements JettyServerCustomizer { connectionFactory); } - private boolean isAlpnPresent() { - return ClassUtils.isPresent("org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory", null); + private boolean isJettyAlpnPresent() { + return ClassUtils.isPresent("org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory", null); } - private boolean isConscryptPresent() { - return ClassUtils.isPresent("org.conscrypt.Conscrypt", null); + private boolean isJettyHttp2Present() { + return ClassUtils.isPresent("org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory", null); } private ServerConnector createHttp2ServerConnector(Server server, HttpConfiguration config, SslContextFactory.Server sslContextFactory) { + HttpConnectionFactory http = new HttpConnectionFactory(config); HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(config); - ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + ALPNServerConnectionFactory alpn = createAlpnServerConnectionFactory(); sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR); - sslContextFactory.setProvider("Conscrypt"); + if (isConscryptPresent()) { + sslContextFactory.setProvider("Conscrypt"); + } SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); - return new SslValidatingServerConnector(server, sslContextFactory, this.ssl.getKeyAlias(), ssl, alpn, h2, - new HttpConnectionFactory(config)); + return new SslValidatingServerConnector(server, sslContextFactory, this.ssl.getKeyAlias(), ssl, alpn, h2, http); + } + + private ALPNServerConnectionFactory createAlpnServerConnectionFactory() { + try { + return new ALPNServerConnectionFactory(); + } + catch (IllegalStateException ex) { + throw new IllegalStateException( + "An 'org.eclipse.jetty:jetty-alpn-*-server' dependency is required for HTTP/2 support.", ex); + } + } + + private boolean isConscryptPresent() { + return ClassUtils.isPresent("org.conscrypt.Conscrypt", null) + && ClassUtils.isPresent("org.eclipse.jetty.alpn.conscrypt.server.ConscryptServerALPNProcessor", null); } /** @@ -225,9 +242,9 @@ class SslServerCustomizer implements JettyServerCustomizer { */ static class SslValidatingServerConnector extends ServerConnector { - private SslContextFactory sslContextFactory; + private final SslContextFactory sslContextFactory; - private String keyAlias; + private final String keyAlias; SslValidatingServerConnector(Server server, SslContextFactory sslContextFactory, String keyAlias, SslConnectionFactory sslConnectionFactory, HttpConnectionFactory connectionFactory) {