read

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

Blog Logo

Eric Helgeson


Published

Image

Agile Orbit

Agile Development and DevOps

Back to Overview