What is WildFly Swarm

WildFly Swarm offers an innovative approach to packaging and running Java EE applications by packaging them with just enough of the server runtime to “java -jar” your application. It’s MicroProfile compatible, too.

WildFly Swarm is capable of producing so-called just enough app-server to support each component of your system.

Packaging Types

50shades

Uberjar

An uberjar is a single Java .jar file that includes everything you need to execute your application, including: your compiled code + direct dependencies + app server.

The uberjar is useful when a single executable binary artifact is produced and moved through the testing, validation, and production environments.

Spring Boot popularized this packaging style, which lets you run the entire application only with a standard Java Runtime environment (plain ol’ java -jar uber.jar).

Wildfly Swarm breaks the whole Wildfly Server into fractions (some providing only a specific API, such as CDI or JAX-RS, other providing higher-level capabilities) and bundles in the uberjar only those required by the code.

Hollow JAR

A hollow jar is similar to an uberjar, but includes only the runtime components, and does not include your application code. So it encloses: direct dependencies + app server, without the compiled code. It’s like a normal Java EE container server, but on a diet!

A hollow jar is suitable for deployment processes that involve Linux containers such as Docker. The application runtime and dependecies remain unchanged so the image layer containing it can be reused across code changes.

This is the packaging we analyze in this article.

Skinny - Thin WAR

The skinny war contain nothing but the application code you compiled (basically class files), this makes a lot of sense in the docker world of layered container images; the thin war is like a traditional web archive incorporating the code and the dependencies.

This is the standard Java EE style, it is thin but requires an application container to run.

Which one is better?

There is no general winner here, pros/cons of each one is trivial, it depends on your needs!

Good news everyone: Wildfly Swarm supports all of them!

Code example

You can grab the code here:

 $ git clone https://github.com/filippobuletto/skinny-on-fat-thin-hollow-and-uber.git

Build the project with mvn clean package:

⇒ ll -Sh target
 69M 19 Gen 14:15 demo-hollow-swarm.jar
 22M 19 Gen 14:15 demo.war.original
6,2K 19 Gen 14:15 demo.war

There are three interesting artifacts:

  1. demo-hollow-swarm.jar: a hollow jar!
  2. demo.war.original: a thin war.
  3. demo.war: a skinny war.

During the Maven build there are three main plugin involved:

  • maven-compiler-plugin: builds application’s class file (the content of the skinny war).
  • maven-war-plugin: builds the thin war.
  • wildfly-swarm-plugin: build the uber/hollow jar and repackages the war artifact into a skinny one.

To start the application (which is in hollow packaging style) is as simple as:

⇒ java -jar target/demo-hollow-swarm.jar target/demo.war

The first lines of log display which part of the Wilfly Subsystem has been packaged in the hollow jar:

Installed fraction:                  Logging - STABLE
Installed fraction:         JAX-RS with JAXB - STABLE
Installed fraction:          Bean Validation - STABLE
Installed fraction:        CDI Configuration - STABLE
Installed fraction:       JAX-RS with JSON-P - STABLE
Installed fraction:                      CDI - STABLE
...

Theese are the fractions (parts) of a Wildfly 11 needed by the demo application, resulting in less than half of a fully packed (and zipped) server.

WFLYSRV0010: Deployed "demo.war" (runtime-name : "demo.war")
WFSWARM99999: WildFly Swarm is Ready

Later in the log our skinny war is deployed and ready to serve requests!

Use the hollow jar like a slim app server

We have already seen how to package and use a Swarm application as a hollow jar + skinny war and this is all fun and games, but every time we make a little change in the source code we have to stop and restart the entire service, this is unacceptable!

With a full Wildfly and thin war (good ol’ Java EE style) this is achieved with a componend named “deployment scanner” which allow the server to notice something in the archive has changed and go for a redeploy of the service.

But wait, Swarm can package all the standard Wildfly components, including the scanner fraction! Normally the swarm plugin includes all the fraction needed automatically using “fraction detection” but because this particular fraction isn’t referenced in the application’s code we have to request it explicitly:

<plugin>
    <groupId>org.wildfly.swarm</groupId>
    <artifactId>wildfly-swarm-plugin</artifactId>
    <configuration>
        <additionalFractions>scanner</additionalFractions>
        <!-- ... -->
    </configuration>
<!-- ... -->

Now we have to configure the fraction and tell it where and how often to search archives, this can be obtained with a portion of Wildfly’s standalone.xml passed as a parameter of the hollow jar:

<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
    <deployment-scanner scan-enabled="true"
        scan-interval="10000" path="${swarm.deployment.path}"
        name="quote-service" auto-deploy-xml="false" />
</subsystem>
⇒ java -jar target/demo-hollow-swarm.jar -c target/standalone.xml

If you now move a newer version of your application to the path defined in the ${swarm.deployment.path} variable you’ll have hot deploy!

Now we can separate our application code from its runtime dependencies, and put them in separate Linux container image layers!

For example these can be:

  1. Base Java image;
  2. Layer with hollow jar;
  3. Layer with skinny war, this can evolve more rapidly than the hollow jar.

Consider this Dockerfile:

FROM java:openjdk-8-jdk

ADD target/demo-hollow-swarm.jar /opt/demo-hollow-swarm.jar
ADD target/demo.war /opt/deploy/demo.war
ADD target/standalone.xml /opt/standalone.xml

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/opt/demo-hollow-swarm.jar", "-c", "/opt/standalone.xml"]

Will lead to:

⇒ docker build -t demo-wildfly .
Sending build context to Docker daemon  121.7MB
Step 1/6 : FROM java:openjdk-8-jdk
 ---> d23bdf5b1b1b
Step 2/6 : ADD target/demo-hollow-swarm.jar /opt/demo-hollow-swarm.jar
 ---> Using cache
 ---> a78ead0b4a79
Step 3/6 : ADD target/demo.war /opt/deploy/demo.war
 ---> Using cache
 ---> f2c12a907ad2
Step 4/6 : ADD target/standalone.xml /opt/standalone.xml
 ---> Using cache
 ---> dbd72df55462
Step 5/6 : EXPOSE 8080
 ---> Using cache
 ---> 01cc0d6f565d
Step 6/6 : ENTRYPOINT java -jar /opt/demo-hollow-swarm.jar -c /opt/standalone.xml
 ---> Using cache
 ---> e70a8c83b6f2
Successfully built e70a8c83b6f2
Successfully tagged demo-wildfly:latest

Developers can be faster at edit/build/test their applications: build and start a uberjar takes about 20 seconds, to do a hot deploy takes about 2 seconds! This will make your CI/CD pipelines faster as well.

References