BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News GraalVM 20.0: Run Tomcat as Native Image on Windows

GraalVM 20.0: Run Tomcat as Native Image on Windows

This item in japanese

Lire ce contenu en français

Bookmarks

GraalVM, a polyglot virtual machine that provides a shared runtime to execute applications written in multiple languages such as Java, Python, and JavaScript, has released major version 20.0 with full support on Windows Platform. The GraalVM 20.0 Windows distribution now includes the JavaScript engine, the GraalVM updater utility gu, and the JDK with the GraalVM compiler enabled. Note that unlike the Linux and MacOS distributions, Node.js support is not yet available on Windows.

GraalVM’s native image generation utility has also been updated to provide extended support on Windows. A native image is an ahead-of-time (AOT) compiled Java bytecode packaged as a standalone executable. The native image typically achieves faster startup time and smaller footprint. The native image utility should be installed using GraalVM updater utility gu. This is a package manager that downloads and installs packages not included in the core distribution of GraalVM.

In a related news, Apache Tomcat 9 has announced full support for GraalVM native image generation that includes the container. However, care must be taken while building Tomcat-based native images since other third party libraries used by Tomcat web apps might not fully support native images. For example, if a library depends on dynamic classloading or reflection, GraalVM substrate VM must first be run using the tracing agent in order to auto generate configuration files used by the native image. These files can be placed under META-INF/native-image of the web app or jar to support features like reflection inside the native image.

The following code example showcases a simple Java 11 class that runs an embedded Tomcat server:

public class TED {

  public static void main(String... args)
      throws Exception {
    File baseFolder = new File(System.getProperty("user.dir"));
    File appsFolder = new File(baseFolder, "web-apps");

    var tomcat = new Tomcat();
    tomcat.setBaseDir(baseFolder.getAbsolutePath());
    tomcat.setPort(8080);
    tomcat.getHost().setAppBase(appsFolder.getAbsolutePath());

    // Call the connector to create the default connector.
    tomcat.getConnector();

    tomcat.addWebapp("", appsFolder.getAbsolutePath());
    var wrapper = tomcat.addServlet("", "hello", new HelloServlet());
    wrapper.setLoadOnStartup(1);
    wrapper.addMapping("/*");

    tomcat.start();
    tomcat.getServer().await();
  }

  private static class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
      resp.setStatus(200);

      var writer = resp.getWriter();
      writer.write("Hello from Tomcat native image!");
      writer.flush();
      writer.close();
    }
  }
}

Use the Maven Shade plugin or the Gradle Shadow Plugin to compile and build the class into an uber JAR as the native-image utility is easier to use with single JARs. Once the uber JAR is created, run the GraalVM tracing agent to generate configuration files for the native image. The following snippet shows how to run GraalVM tracing agent to generate configuration files for reflection, Java Native Interface (JNI), classpath resources, and dynamic proxies:

java \
  -agentlib:native-image-agent=config-merge-dir=graal-conf \
  -cp build/libs/ted-1.0-all.jar my.example.TED

The tracing agent creates the various configuration files in JSON that can be passed to the native-image utility:

native-image --no-server \
  -cp build/libs/ted-0.0.1-SNAPSHOT-all.jar \
  --allow-incomplete-classpath \
  -H:+JNI -H:+ReportUnsupportedElementsAtRuntime \
  -H:+ReportExceptionStackTraces -H:EnableURLProtocols=http,jar,jrt \
  -H:ConfigurationFileDirectories=graal-conf/ \
  -H:ReflectionConfigurationFiles=graal-conf/reflect-config.json \
  -H:ResourceConfigurationFiles=graal-conf/resource-config.json \
  -H:JNIConfigurationFiles=graal-conf/jni-config.json \
  my.example.TED ted

In the example above, the utility creates a native binary ted with a file size of around 40MB. It can be run without a full JDK or JRE:

./ted

Navigate to http://localhost:8006 and you will be greeted with a hello message as defined in the example Java class:

Hello from Tomcat native image!

Note that several Tomcat features like Java serialization, JMX, JULI, and static linking of tomcat-native are not yet supported inside GraalVM native image.

In addition to native image improvements and Windows support, GraalVM’s implementation of the WebAssembly language, GraalWasm, is now available as an experimental feature. Using the polyglot API, webassembly binaries can be embedded and run from Java applications.

Another noteworthy change to Java in GraalVM is that the default setting for ThreadPriorityPolicy is set to 1. This means that thread priorities set in Java are reflected by native OS thread priorities. Care must be taken while migrating performance sensitive applications as the default ThreadPriorityPolicy may affect application performance.

This release of GraalVM fixed several JNI and JDK 11 issues related to native image generation. A new JDK Flight Recorder Data Viewer has been added to GraalVM VisualVM, an enhanced version of VisualVM. Runtimes of NodeJS, Ruby, and LLVM have also been upgraded. A technology preview of the Language Server Protocol implementation for GraalVM languages is available in GraalVM VSCode Extensions.

Both JDK 8 and JDK 11 based GraalVM distributions are available for download from GitHub.

Rate this Article

Adoption
Style

BT