Micronaut Servlet

Provides integration between Micronaut and the Servlet API

Version: 4.12.0

1 Introduction

This project implements a Micronaut HTTP server backed onto the Servlet API and includes various subprojects that allow running popular Servlet containers as servers.

This project is for users who fall into one of the following categories:

  • Users who want to use Micronaut but the target deployment environment is based on Servlets

  • Users who prefer the thread per connection model of the Servlet API over the Event Loop model provided by the default Netty-based HTTP server

  • Users who have existing Servlets and/or Filters that they wish to combine with Micronaut.

2 Release History

For this project, you can find a list of releases (with release notes) here:

3 Working with the Servlet API

In general you can follow the documentation for the HTTP server when building applications. All non-Netty specific features of the default HTTP server should work the same for Servlet containers (Report an issue if you find a difference).

There are a couple of additional extensions within Micronaut Servlet that make it easier to work with the Servlet API which are detailed in the following sections.

Injecting the Servlet Request and Response

You can receive the HttpServletRequest and HttpServletResponse objects directly as parameters:

Using the Request and Response
@Get("/hello")
void process(
        HttpServletRequest request, (1)
        HttpServletResponse response) (2)
        throws IOException {
    response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
    response.setStatus(HttpStatus.ACCEPTED.getCode());
    try (final PrintWriter writer = response.getWriter()) {
        writer.append("Hello ").append(request.getParameter("name"));
        writer.flush();
    }
}
1 The request object
2 The response object

Simplified I/O code with Readable and Writable

Writing to the response and reading from the request can be simplified with Micronaut’s Readable and Writable interfaces:

Using Readable and Writable
import io.micronaut.core.io.Readable;
import io.micronaut.core.io.Writable;

@Post(value = "/writable", processes = "text/plain")
Writable readAndWrite(@Body Readable readable) throws IOException {
    return out -> {
        try (BufferedReader reader = new BufferedReader(readable.asReader())) {
            out.append("Hello ").append(reader.readLine());
        }
    };
}

Multipart support with @Part

Multipart support is improved with the ability to inject parts using the annotation io.micronaut.http.annotation.Part. For example:

Using @Part
@Post(value = "/multipart", consumes = MediaType.MULTIPART_FORM_DATA, produces = "text/plain")
String multipart(
        String attribute, (1)
        @Part("one") Person person, (2)
        @Part("two") String text, (3)
        @Part("three") byte[] bytes, (4)
        @Part("four") jakarta.servlet.http.Part raw, (5)
        @Part("five") CompletedPart part) { (6)
    return "Ok";
}
1 You can receive attributes with just parameter names that match the attribute name
2 Parts that have a content type of application/json can be bound to POJOs
3 You can read parts as text
4 You can read parts as byte[]
5 You can receive the raw jakarta.servlet.http.Part
6 You can receive Micronaut’s CompletedPart interface which works with Netty too

4 Servlet Annotation Support

To use the Servlet APIs annotations to register servlets, filters and listeners you first need to add the following annotation processor dependency:

annotationProcessor("io.micronaut.servlet:micronaut-servlet-processor")
<annotationProcessorPaths>
    <path>
        <groupId>io.micronaut.servlet</groupId>
        <artifactId>micronaut-servlet-processor</artifactId>
    </path>
</annotationProcessorPaths>

The following annotations can then be used from the Servlet API to add additional servlets, filters and listeners as beans:

  • @WebFilter - Applicable to types that implement the jakarta.servlet.Filter interface.

  • @WebServlet - Applicable to types that implement the jakarta.servlet.Servlet interface.

  • @WebListener - See the annotation javadoc for applicable types.

The @Order annotation can be used to control registration order and hence filter order. For example a value of io.micronaut.core.order.Ordered.HIGHEST_PRECEDENCE will run the filter first.

Using HIGHEST_PRECEDENCE will prevent any other filter running before your filter. The default position is 0 and HIGHEST_PRECEDENCE == Integer.MIN_VALUE hence you should consider using constants to the represent the position of your filter that exist somewhere between HIGHEST_PRECEDENCE and LOWEST_PRECEDENCE.

In addition, you can use the following annotations on methods of @Factory beans to instantiate servlets and filters and register them:

The following example adds a new Servlet filter with the highest precedence:

Adding a Filter with a Factory
import io.micronaut.context.annotation.Factory;
import io.micronaut.core.annotation.Order;
import io.micronaut.core.order.Ordered;
import io.micronaut.servlet.api.annotation.ServletFilterBean;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.GenericFilter;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;

@Factory // (1)
public class MyFilterFactory {

    @ServletFilterBean(
        filterName = "another", // (2)
        value = {"/extra-filter/*", "${my.filter.mapping}"}) // (3)
    @Order(Ordered.HIGHEST_PRECEDENCE) // (4)
    Filter myOtherFilter() {
        return new GenericFilter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
                request.setAttribute("runFirst", true);
                chain.doFilter(request, response);
            }
        };
    }
}
1 A @Factory bean is defined
2 The @ServletFilterBean annotation is used and a filter name defined
3 1 or more mappings are defined. Note these can be resolved from property placeholder configuration if necessary.
4 The order of the filter is defined.
Servlet Filters are not to be confused with Micronaut filters. Servlet Filters always run before the Micronaut Servlet which in turn runs the Micronaut Filters hence it is not possible to place a Servlet Filter after Micronaut Filters.

5 WAR Deployment

To deploy as a WAR file you need to make some adjustments to your dependencies.

First make the server you are using a developmentOnly dependency (or provided in Maven):

developmentOnly("io.micronaut.servlet:micronaut-http-server-jetty")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-server-jetty</artifactId>
    <scope>provided</scope>
</dependency>

Then make sure you include micronaut-servlet-engine dependency in your build configuration:

implementation("io.micronaut.servlet:micronaut-servlet-engine")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-servlet-engine</artifactId>
</dependency>

Then alter your build configuration to build a WAR file. In Gradle this can be done by applying the WAR plugin:

Applying the Gradle WAR plugin
plugins {
    id "war"
    id "application"
}

You can then build the WAR file and deploy it to the Servlet container as per the instructions provided by the container.

Micronaut will load using MicronautServletInitializer which registers the DefaultMicronautServlet instance.

5.1 Container version considerations

Micronaut 4.0.0 switched to using the new jakarta.servlet package for Servlet API classes. This means that Micronaut 4.0.0+ WAR files will not run on Servlet containers that do not support the jakarta.servlet package.

For example, Tomcat 10 switched to the jakarta.servlet package, so Micronaut 4.0.0 is required to run as a WAR on Tomcat 10. And Micronaut 4.0.0 WAR files cannot be run on Tomcat 9 or earlier.

If you have a Micronaut 3 based WAR file that you wish to deploy to Tomcat 10, you need to deploy it to the $CATALINA_BASE/webapps-javaee directory instead of the usual $CATALINA_BASE/webapps, and Tomcat will perform a conversion to jakarta.servlet.

5.2 External Configuration

In a standalone Micronaut Framework application, external property sources for configuration can be configured via the Java system property micronaut.config.files or the environment variable MICRONAUT_CONFIG_FILES. When running as a WAR file, this can be problematic if you wish to run multiple Micronaut Framework WARs in the same container, as all applications will share the same location.

To allow an external location per application, it is necessary to write our own replacement for MicronautServletInitializer. The following example will look for configuration in the /tmp directory and on the classpath in the /some/path directory.

src/main/java/example/CustomMicronautServletInitializer.java
package example;

import io.micronaut.context.ApplicationContext;
import io.micronaut.context.ApplicationContextBuilder;
import io.micronaut.servlet.engine.initializer.MicronautServletInitializer;
import jakarta.servlet.ServletContext;

public class CustomInitializer extends MicronautServletInitializer {

    @Override
    protected ApplicationContextBuilder buildApplicationContext(ServletContext ctx) {
        return ApplicationContext
                .builder()
                .overrideConfigLocations(
                    "file:/tmp",
                    "classpath:/some/path"
                )
                .classLoader(ctx.getClassLoader())
                .singletons(ctx);
    }
}

We can then use Java’s Service Provider Interface to register this class as the initializer by pointing to it in the META-INF/services/jakarta.servlet.ServletContainerInitializer file.

src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
example.CustomInitializer
Some servlet containers may limit the locations that are accessible from applications for security reasons.

5.3 WAR Context path

If you are deploying the WAR to the root context — for example by renaming the WAR to ROOT.war prior to deployment — then the context path may be overridden by configuring micronaut.server.context-path in your application configuration.

If you are deploying a WAR called myproject-1.0.war to Tomcat, Jetty, etc. the context path will be set to /myproject-1.0, and cannot be overridden via application configuration.

6 Jetty Server

To use Jetty as a server add the following dependency:

implementation("io.micronaut.servlet:micronaut-http-server-jetty")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-server-jetty</artifactId>
</dependency>

Jetty is supported with GraalVM native image
If you plan to produce a WAR file then the dependency should be developmentOnly.

To customize the Jetty server you can use the following configuration properties:

🔗
Table 1. Configuration Properties for JettyConfiguration
Property Type Description

micronaut.server.jetty.customizers

java.util.List

micronaut.server.jetty.output-buffer-size

int

micronaut.server.jetty.output-aggregation-size

int

micronaut.server.jetty.request-header-size

int

micronaut.server.jetty.response-header-size

int

micronaut.server.jetty.header-cache-size

int

micronaut.server.jetty.header-cache-case-sensitive

boolean

micronaut.server.jetty.secure-port

int

micronaut.server.jetty.secure-scheme

java.lang.String

micronaut.server.jetty.persistent-connections-enabled

boolean

micronaut.server.jetty.idle-timeout

long

micronaut.server.jetty.send-server-version

boolean

micronaut.server.jetty.send-xpowered-by

boolean

micronaut.server.jetty.send-date-header

boolean

micronaut.server.jetty.delay-dispatch-until-content

boolean

micronaut.server.jetty.use-input-direct-byte-buffers

boolean

micronaut.server.jetty.use-output-direct-byte-buffers

boolean

micronaut.server.jetty.form-encoded-methods

java.lang.String

micronaut.server.jetty.max-error-dispatches

int

micronaut.server.jetty.min-request-data-rate

long

micronaut.server.jetty.min-response-data-rate

long

micronaut.server.jetty.http-compliance

org.eclipse.jetty.http.HttpCompliance

micronaut.server.jetty.uri-compliance

org.eclipse.jetty.http.UriCompliance

micronaut.server.jetty.request-cookie-compliance

org.eclipse.jetty.http.CookieCompliance

micronaut.server.jetty.response-cookie-compliance

org.eclipse.jetty.http.CookieCompliance

micronaut.server.jetty.multi-part-form-data-compliance

org.eclipse.jetty.server.MultiPartFormDataCompliance

micronaut.server.jetty.notify-remote-async-errors

boolean

micronaut.server.jetty.relative-redirect-allowed

boolean

micronaut.server.jetty.local-address

java.net.SocketAddress

micronaut.server.jetty.server-authority

org.eclipse.jetty.util.HostPort

micronaut.server.jetty.init-parameters

java.util.Map

Or you can register a BeanCreatedEventListener:

Jetty Server Customization
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import org.eclipse.jetty.server.Server;
import jakarta.inject.Singleton;

@Singleton
public class JettyServerCustomizer implements BeanCreatedEventListener<Server> {
    @Override
    public Server onCreated(BeanCreatedEvent<Server> event) {
        Server jettyServer = event.getBean();
        // perform customizations...
        return jettyServer;
    }
}

Access Log Configuration

To configure the Jetty Access Log:

Jetty Access Log Configuration
micronaut.server.jetty.access-log.enabled=true
micronaut.server.jetty.access-log.filename=/tmp/access.log
micronaut.server.jetty.access-log.retain-days=10
micronaut.server.jetty.access-log.pattern=%{client}a - %u %t "%r" %s %O
micronaut.server.jetty.access-log.enabled: true
micronaut.server.jetty.access-log.filename: /tmp/access.log
micronaut.server.jetty.access-log.retain-days: 10
micronaut.server.jetty.access-log.pattern: >
    %{client}a - %u %t "%r" %s %O
"micronaut.server.jetty.access-log.enabled"=true
"micronaut.server.jetty.access-log.filename"="/tmp/access.log"
"micronaut.server.jetty.access-log.retain-days"=10
"micronaut.server.jetty.access-log.pattern"="%{client}a - %u %t \"%r\" %s %O"
micronaut.server.jetty.accessLog.enabled = true
micronaut.server.jetty.accessLog.filename = "/tmp/access.log"
micronaut.server.jetty.accessLog.retainDays = 10
micronaut.server.jetty.accessLog.pattern = "%{client}a - %u %t \"%r\" %s %O"
{
  "micronaut.server.jetty.access-log.enabled" = true
  "micronaut.server.jetty.access-log.filename" = "/tmp/access.log"
  "micronaut.server.jetty.access-log.retain-days" = 10
  "micronaut.server.jetty.access-log.pattern" = "%{client}a - %u %t \"%r\" %s %O"
}
{
  "micronaut.server.jetty.access-log.enabled": true,
  "micronaut.server.jetty.access-log.filename": "/tmp/access.log",
  "micronaut.server.jetty.access-log.retain-days": 10,
  "micronaut.server.jetty.access-log.pattern": "%{client}a - %u %t \"%r\" %s %O"
}

7 Tomcat Server

To use Tomcat as a server add the following dependency:

implementation("io.micronaut.servlet:micronaut-http-server-tomcat")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-server-tomcat</artifactId>
</dependency>

Tomcat is supported with GraalVM native image
If you plan to produce a WAR file then the dependency should be developmentOnly.

To customize the Tomcat server you can use the following configuration properties:

🔗
Table 1. Configuration Properties for TomcatConfiguration
Property Type Description

micronaut.server.tomcat.protocol

java.lang.String

micronaut.server.tomcat.throw-on-failure

boolean

micronaut.server.tomcat.domain

java.lang.String

micronaut.server.tomcat.service

org.apache.catalina.Service

micronaut.server.tomcat.allow-backslash

boolean

micronaut.server.tomcat.allow-trace

boolean

micronaut.server.tomcat.async-timeout

long

micronaut.server.tomcat.discard-facades

boolean

micronaut.server.tomcat.enable-lookups

boolean

micronaut.server.tomcat.enforce-encoding-in-get-writer

boolean

micronaut.server.tomcat.max-cookie-count

int

micronaut.server.tomcat.max-parameter-count

int

micronaut.server.tomcat.max-post-size

int

micronaut.server.tomcat.max-save-post-size

int

micronaut.server.tomcat.parse-body-methods

java.lang.String

micronaut.server.tomcat.port

int

micronaut.server.tomcat.port-offset

int

micronaut.server.tomcat.proxy-name

java.lang.String

micronaut.server.tomcat.proxy-port

int

micronaut.server.tomcat.redirect-port

int

micronaut.server.tomcat.scheme

java.lang.String

micronaut.server.tomcat.secure

boolean

micronaut.server.tomcat.uriencoding

java.lang.String

micronaut.server.tomcat.use-body-encoding-for-uri

boolean

micronaut.server.tomcat.xpowered-by

boolean

micronaut.server.tomcat.use-ipvhosts

boolean

micronaut.server.tomcat.encoded-solidus-handling

java.lang.String

micronaut.server.tomcat.reject-suspicious-uris

boolean

Or you can register a BeanCreatedEventListener:

Tomcat Server Customization
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import org.apache.catalina.startup.Tomcat;
import jakarta.inject.Singleton;

@Singleton
public class TomcatServerCustomizer implements BeanCreatedEventListener<Tomcat> {
    @Override
    public Tomcat onCreated(BeanCreatedEvent<Tomcat> event) {
        Tomcat tomcat = event.getBean();
        // perform customizations...
        return tomcat;
    }
}

Access Log Configuration

To configure the Tomcat Access Log:

Tomcat Access Log Configuration
micronaut.server.tomcat.access-log.enabled=true,
micronaut.server.tomcat.access-log.pattern=combined
micronaut.server.tomcat.access-log.directory=/var/logs
micronaut.server.tomcat.access-log.enabled: true,
micronaut.server.tomcat.access-log.pattern: combined
micronaut.server.tomcat.access-log.directory: /var/logs
"micronaut.server.tomcat.access-log.enabled"="true,"
"micronaut.server.tomcat.access-log.pattern"="combined"
"micronaut.server.tomcat.access-log.directory"="/var/logs"
micronaut.server.tomcat.accessLog.enabled = "true,"
micronaut.server.tomcat.accessLog.pattern = "combined"
micronaut.server.tomcat.accessLog.directory = "/var/logs"
{
  "micronaut.server.tomcat.access-log.enabled" = "true,"
  "micronaut.server.tomcat.access-log.pattern" = "combined"
  "micronaut.server.tomcat.access-log.directory" = "/var/logs"
}
{
  "micronaut.server.tomcat.access-log.enabled": "true,",
  "micronaut.server.tomcat.access-log.pattern": "combined",
  "micronaut.server.tomcat.access-log.directory": "/var/logs"
}

8 Undertow Server

To use Undertow as a server add the following dependency:

implementation("io.micronaut.servlet:micronaut-http-server-undertow")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-server-undertow</artifactId>
</dependency>

Undertow is not supported with GraalVM native image. Use Jetty or Tomcat if native image support is required. See UNDERTOW-1408.
If you plan to produce a WAR file then the dependency should be developmentOnly.

To customize the Undertow server you can use the following configuration properties:

🔗
Table 1. Configuration Properties for UndertowConfiguration
Property Type Description

micronaut.server.undertow.buffer-size

int

micronaut.server.undertow.io-threads

int

micronaut.server.undertow.worker-threads

int

micronaut.server.undertow.direct-buffers

boolean

micronaut.server.undertow.handler

io.undertow.server.HttpHandler

micronaut.server.undertow.worker

org.xnio.XnioWorker

micronaut.server.undertow.ssl-engine-delegated-task-executor

java.util.concurrent.Executor

micronaut.server.undertow.byte-buffer-pool

io.undertow.connector.ByteBufferPool

micronaut.server.undertow.worker-options

java.util.Map

micronaut.server.undertow.socket-options

java.util.Map

micronaut.server.undertow.server-options

java.util.Map

Or you can register a BeanCreatedEventListener:

Undertow Server Customization
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.undertow.Undertow;
import jakarta.inject.Singleton;

@Singleton
public class UndertowServerCustomizer implements BeanCreatedEventListener<Undertow.Builder> {
    @Override
    public Undertow.Builder onCreated(BeanCreatedEvent<Undertow.Builder> event) {
        Undertow.Builder undertowBuilder = event.getBean();
        // perform customizations...
        return undertowBuilder;
    }
}

Access Log Configuration

To configure the Undertow Access Log:

Undertow Access Log Configuration
micronaut.server.undertow.access-log.enabled=true,
micronaut.server.undertow.access-log.pattern=combined
micronaut.server.undertow.access-log.output-directory=/var/logs
micronaut.server.undertow.access-log.enabled: true,
micronaut.server.undertow.access-log.pattern: combined
micronaut.server.undertow.access-log.output-directory: /var/logs
"micronaut.server.undertow.access-log.enabled"="true,"
"micronaut.server.undertow.access-log.pattern"="combined"
"micronaut.server.undertow.access-log.output-directory"="/var/logs"
micronaut.server.undertow.accessLog.enabled = "true,"
micronaut.server.undertow.accessLog.pattern = "combined"
micronaut.server.undertow.accessLog.outputDirectory = "/var/logs"
{
  "micronaut.server.undertow.access-log.enabled" = "true,"
  "micronaut.server.undertow.access-log.pattern" = "combined"
  "micronaut.server.undertow.access-log.output-directory" = "/var/logs"
}
{
  "micronaut.server.undertow.access-log.enabled": "true,",
  "micronaut.server.undertow.access-log.pattern": "combined",
  "micronaut.server.undertow.access-log.output-directory": "/var/logs"
}

9 HTTP POJA Application

HTTP POJA allows creating Micronaut applications that consume respond to HTTP requests with streams. By default, the application will read requests from standard input stream and write responses to standard output. The requests can only be answered in a serial manner. Currently HTTP POJA is based on Apache HTTP Core library.

This feature allows creating simple applications that launch and respond on demand with minimal overhead. The module is suitable for usage with systemd on Linux or launchd on MacOS. Examples are given below.

To use the HTTP POJA feature add the following dependencies:

implementation("io.micronaut.servlet:micronaut-http-poja-apache")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-poja-apache</artifactId>
</dependency>

testImplementation("io.micronaut.servlet:micronaut-http-poja-test")
<dependency>
    <groupId>io.micronaut.servlet</groupId>
    <artifactId>micronaut-http-poja-test</artifactId>
    <scope>test</scope>
</dependency>

To customize the HTTP POJA you can use the following configuration properties:

🔗
Table 1. Configuration Properties for ApacheServletConfiguration
Property Type Description

poja.apache.input-buffer-size

int

The size of the buffer that is used to read and parse the HTTP request (in bytes). Default value is 8192 (8Kb).

poja.apache.output-buffer-size

int

The size of the buffer that is used to write the HTTP response (in bytes). Default value is 8192 (8Kb).

poja.apache.use-inherited-channel

boolean

When true, the inherited channel will be used by if present. Otherwise, STDIN and STDOUT will be used.

Use HTTP POJA with launchd on MacOS

If you have built a HTTP POJA application as a native image executable, create the following plist file and replace [executable] with your executable path.

If you are unfamiliar with building native image executables refer to Micronaut Creating First Graal App guide.
If you do not wish to use native image prepend java and -jar program arguments and use the jar instead.
~/Library/LaunchAgents/com.example.poja.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example.poja</string>

    <key>Enabled</key>
    <false/>

    <key>ProgramArguments</key>
    <array>
        <string>[executable]</string>
        <string>-Dpoja.apache.useInheritedChannel=false</string>
    </array>

    <key>Sockets</key>
    <dict>
      <key>Listeners</key>
      <dict>
        <key>SockServiceName</key>
        <string>8080</string>
        <key>SockType</key>
        <string>stream</string>
        <key>SockProtocol</key>
        <string>TCP</string>
      </dict>
    </dict>

    <key>StandardErrorPath</key>
    <string>/tmp/com.example.poja.log</string>

    <key>inetdCompatibility</key>
    <dict>
      <key>Wait</key>
      <false/>
    </dict>

    <key>KeepAlive</key>
    <false/>
  </dict>
</plist>

Load the plist file with launchd:

launchctl load ~/Library/LaunchAgents/com.example.poja.plist

Then the configured application will respond on port 8080:

curl localhost:8080

Use HTTP POJA with systemd on Linux

If you have built a HTTP POJA application as a native image executable, create the following files and replace [executable] with your executable path.

If you are unfamiliar with building native image executables refer to Micronaut Creating First Graal App guide.
If you do not wish to use native image prepend java and -jar program arguments and use the jar instead.
/etc/systemd/system/examplepoja.socket
[Unit]
Description=Socket to launch poja example on incoming connection

[Socket]
ListenStream=127.0.0.1:8080
Accept=yes

[Install]
WantedBy=sockets.target
/etc/systemd/system/examplepoja@.service
[Unit]
Description=Example Poja Service
Requires=examplepoja.socket

[Service]
Type=simple
ExecStart=[executable] -Dpoja.apache.useInheritedChannel=false
ExecStop=/bin/kill $MAINPID
KillMode=process
StandardInput=socket
StandardOutput=socket
StandardError=journal

[Install]
WantedBy=multi-user.target

Change selinux policy to allow systemd to use executable in the desired location with:

chcon -R -t bin_t [executable parent directory]

Enable and start listening on the socket with systemctl:

sudo systemctl enable examplepoja.socket
sudo systemctl start examplepoja.socket

Then the configured application will respond on port 8080:

curl localhost:8080

Use HTTP POJA with systemd-socket-activate on Linux

To test your application with systemd-socket-activate run:

systemd-socket-activate --inetd -a -l /tmp/http-poja.sock [executable]

In a separate terminal send a request to the socket:

curl --unix-socket /tmp/http-poja.sock http://localhost/

10 Known Issues

There are some known issues with Servlet integration to the Micronaut Framework

HttpProxyClient and Server Filters

It is not currently possible to use the HttpProxyClient with Servlet Filters.

Error handlers re-reading the request body

Local error handlers that require the request body to be reparsed will not work in Servlet based applications. The body is read from the request input-stream and so attempting to reparse it for the error handler will fail.

11 FAQ

Where can I find the source code?

You can find the source code of this project in this repository:

How do I configure Multipart handling?

Multipart handling is disabled by default. You can enable it with the following configuration properties.

How do I configure Static Resource handling for the embedded server?

Static resources are not enabled by default. See Serving Static Resources for how to configure paths to static resources.

How do I enable HTTPS for the embedded server?

12 Breaking Changes

This section documents breaking changes between versions.

3.3.4

Binding network interface

Previously, the default servlet engine will bind to all network interfaces. This is a security risk. Now, the default servlet engine will bind to localhost only. To restore the original functionality, you need to configure micronaut.server.host, or set the HOST environment variable.

13 Repository

You can find the source code of this project in this repository: