@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();
}
}
Micronaut Servlet
Provides integration between Micronaut and the Servlet API
Version:
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:
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:
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:
@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 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:
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. |
4.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.
4.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.
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.
example.CustomInitializer
Some servlet containers may limit the locations that are accessible from applications for security reasons. |
4.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.
5 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:
Property | Type | Description |
---|---|---|
|
java.util.List |
|
|
int |
|
|
int |
|
|
int |
|
|
int |
|
|
int |
|
|
boolean |
|
|
int |
|
|
java.lang.String |
|
|
boolean |
|
|
long |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
java.lang.String |
|
|
int |
|
|
long |
|
|
long |
|
|
org.eclipse.jetty.http.HttpCompliance |
|
|
org.eclipse.jetty.http.UriCompliance |
|
|
org.eclipse.jetty.http.CookieCompliance |
|
|
org.eclipse.jetty.http.CookieCompliance |
|
|
org.eclipse.jetty.server.MultiPartFormDataCompliance |
|
|
boolean |
|
|
boolean |
|
|
java.net.SocketAddress |
|
|
org.eclipse.jetty.util.HostPort |
|
|
java.util.Map |
Or you can register a BeanCreatedEventListener
:
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;
}
}
6 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:
Property | Type | Description |
---|---|---|
|
java.lang.String |
|
|
boolean |
|
|
java.lang.String |
|
|
org.apache.catalina.Service |
|
|
boolean |
|
|
boolean |
|
|
long |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
int |
|
|
int |
|
|
int |
|
|
int |
|
|
java.lang.String |
|
|
int |
|
|
int |
|
|
java.lang.String |
|
|
int |
|
|
int |
|
|
java.lang.String |
|
|
boolean |
|
|
java.lang.String |
|
|
boolean |
|
|
boolean |
|
|
boolean |
|
|
java.lang.String |
|
|
boolean |
Or you can register a BeanCreatedEventListener
:
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;
}
}
7 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:
Property | Type | Description |
---|---|---|
|
int |
|
|
int |
|
|
int |
|
|
boolean |
|
|
io.undertow.server.HttpHandler |
|
|
org.xnio.XnioWorker |
|
|
java.util.concurrent.Executor |
|
|
io.undertow.connector.ByteBufferPool |
|
|
java.util.Map |
|
|
java.util.Map |
|
|
java.util.Map |
Or you can register a BeanCreatedEventListener
:
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;
}
}
8 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.
9 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?
See Securing the Server with HTTPS and the configuration properties for ServerSslConfiguration.
10 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.
11 Repository
You can find the source code of this project in this repository: