Grails 3 uses Tomcat 8 by default, but thanks to Spring Boot it’s easy to change out the underling servlet container to another container such as Undertow or Jetty. One reason to do this would be if you want to take advantage of the different runtime characteristics of Undertow such as http/2 (multiplexing)[0], lightweight memory footprint, and async io (xnio)[1].
In this quick demo, we’ll show how to switch a Grails 3 app to use Undertow and configure it to use the new http/2 standard.
Configuration:
First, lets comment out Tomcat in favor of Undertow build.gradle
:
dependencies {
// compile "org.springframework.boot:spring-boot-starter-tomcat"
compile "org.springframework.boot:spring-boot-starter-undertow"
}
Next we have to customize the embeddedServletContainerFactory
bean to setup HTTP/2.
Add this method to your grails-app/init/<pkg>/Application.groovy
:
@Bean
UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory(){
UndertowEmbeddedServletContainerFactory factory=new UndertowEmbeddedServletContainerFactory();
factory.addBuilderCustomizers(new UndertowBuilderCustomizer(){
@Override public void customize(Undertow.Builder builder){
builder.setBufferSize(1024 * 32)
.setIoThreads(Runtime.getRuntime().availableProcessors() * 2)
.setServerOption(UndertowOptions.ENABLE_HTTP2, true)
.setWorkerThreads(64)
// There are many more options, see the documentation for more.
}
});
return factory;
}
TLS
http/2 does not require a TLS connection per the spec, but Undertow only enables http/2 if the connection is secure. This means we’ll need to setup a private key and certificate.
Create and set a keystore
Create a self signed key
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048
In grails-app/config/application.yml
set the keystore, port and secrets
server:
port: 8443
ssl:
key-store: /path/to/keystore.jks
key-store-password: changeit
key-password: password
Get ALPN
ALPN stands for Application Layer Protocol Negotiation, and is a TLS extension that allows a client to negotiate the next protocol to use after the TLS handshake is complete.
ALPN is currently not included in Java 8. So we’ll have to download it and include it in our Java command options when running with http/2:
IMPORTANT: The version of ALPN is specific to the JDK version you are using. You can find the version for your specific JDK version here: https://eclipse.org/jetty/documentation/current/alpn-chapter.html
# When running the app include this in your `-Xbootclasspath/p:`
wget http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.6.v20151105/alpn-boot-8.1.6.v20151105.jar
Running
To pass the -Xbootclasspath/p
options to Gradle we’ll need to add this at to our bootRun
task in build.gradle
:
bootRun {
systemProperties = System.properties
}
# Running in Dev
./gradlew bootRun -Xbootclasspath/p:build/libs/alpn-boot-8.1.6.v20151105.jar
# Running as standalone jar
./gradlew assemble
cd build/libs
# Remember to include the alpn lib
java -Xbootclasspath/p:alpn-boot-8.1.6.v20151105.jar -jar myapp.war
- You can see the Protocol Version is listed as
HTTP/2.0
Conclusion
It’s easy to change the container a Grails 3 app is running in to fit your workload. Tomcat, Undertow, and Jetty are all available from Spring Boot to use in Grails 3.
Notes
- Tested on JDK 8u66, Grails 3.1.5
- [0] - https://http2.github.io/faq/
- [1] - http://undertow.io/
- http://undertow.io/blog/2015/04/27/An-in-depth-overview-of-HTTP2.html
- https://github.com/making/demo-http2