Building a GraalVM native image of an ActiveJ HTTP Server
In this tutorial we will build the HTTP Server from the getting started tutorial as a GraalVM native image.
Download and run the server
First, clone ActiveJ locally:
git clone -b examples-6.0-beta2 https://github.com/activej/activej.git
Then open the project in your IDE of choice. Before running the example, build the project (Ctrl + F9 for IntelliJ IDEA).
Navigate to a HelloWorldHttpServer class, which is located at activej/examples/tutorials/native-image
and run its main
method. Open your favourite browser and go to localhost:8080
You can see that it is a simple "Hello world" web server:
public class HelloWorldHttpServer extends HttpServerLauncher {
@Provides
AsyncServlet servlet() {
return request -> HttpResponse.ok200()
.withPlainText("Hello, world!")
.toPromise();
}
public static void main(String[] args) throws Exception {
new HelloWorldHttpServer().launch(args);
}
}
Actually, the server is the same as in a getting started tutorial. To build it as a native image we would need a few more things.
Native image prerequisites
First things first, you need to have GraalVM and native-image tool installed as described here.
Maven plugin configuration
We will use the native image maven plugin to simplify build process.
For that we will add the native image plugin to a custom native
profile of our pom.xml :
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.17</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<mainClass>HelloWorldHttpServer</mainClass>
<imageName>hello-world-server</imageName>
<buildArgs>
<buildArg>--no-fallback</buildArg>
<buildArg>--allow-incomplete-classpath</buildArg>
<buildArg>-H:ReflectionConfigurationFiles=${project.basedir}/config/reflectionconfig.json
</buildArg>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
You can read more about plugin configuration at the official plugin documentation page
Although we use a plugin to simplify a build process, a native-image
tool can be used directly if needed.
Reflection configuration
In order to allow reflective operations (required to process ActiveJ Inject annotations) we have to define
a reflection configuration. We did this in a reflectionconfig.json file
inside the config
directory. A file describes a few classes with a required reflection access for fields and methods:
[
{
"name": "HelloWorldHttpServer",
"allDeclaredMethods": true
},
{
"name": "io.activej.launchers.http.HttpServerLauncher",
"allDeclaredFields": true,
"allDeclaredMethods": true
},
{
"name": "io.activej.service.ServiceGraphModule",
"allDeclaredMethods": true
}
]
Building a native image
To build a native image execute mvn -Pnative package
command from within the 'native-image' module directory.
Running a native image
To run a native image execute ./target/hello-world-server
command from within 'native-image' module directory.
You should see that the server is launched and that it is listening on port 8080
.
Open your favourite browser and go to localhost:8080.