Micronaut for Spring

Extensions to integrate Micronaut and Spring

Version:

1 Introduction

Micronaut uses Ahead of Time (AOT) compilation to pre-compute your applications requirements at compile time. The result of this is significantly lower memory requirements, faster startup time, and reflection free framework infrastructure.

This project consists of various components that make it easier to:

  • Integrate Spring components into a Micronaut application

  • Run Spring applications as Micronaut applications

  • Expose Micronaut Beans to a Spring Application

To achieve this the project provides the ability to use a subset of the Spring Annotation-Based programming model to build Micronaut applications. The goal is not necessarily to provide an alternative runtime for Spring, but instead to enable the ability to build libraries that work with both Spring and Micronaut.

2 Release History

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

3 Transforming Spring Applications into Micronaut Applications

Micronaut for Spring allows you to use traditional Spring annotations which are mapped to Micronaut annotations at compilation time. This allows you to write an application that can be imported to another Spring or Micronaut application without change.

Unlike traditional runtime reflection based frameworks Micronaut uses Ahead of Time (AOT) compilation, hence there is no runtime overhead to supporting an additional set of annotations (in this case Spring’s annotation programming model).

As part of this project an Example Application is provided that includes no dependencies on Micronaut itself in the source code (only Spring dependencies) but is computed into a Micronaut application at compilation time.

The value in this as follows:

  • You can take the compiled application and include it into another Spring or Micronaut application without change, which is a huge win for library authors.

  • If you have an existing team of Spring developers they can be up and running with Micronaut without learning a new annotation DSL.

  • Existing tooling like IntelliJ IDEA and STS 4.0 "Just Work" with Micronaut

In addition, the guide for Application Class - Spring Boot to Micronaut Framework compares the application class of a Spring Boot application to that of a Micronaut Framework application.

Note that Spring is huge and only a subset of Spring is supported, but enough to build real applications and libraries that work with either Micronaut or Spring. The following documentation covers the annotations and Spring interfaces that are supported.

If an annotation or interface of Spring is not mentioned in this documentation consider it unsupported.

3.1 Build Configuration

For a build configuration example for Gradle or Maven, see the example project that is part of the guide Run a Spring Boot Application as a Micronaut Application.

3.2 Supported Spring Annotations

The following table summarizes the annotations that Micronaut for Spring supports and the Micronaut annotation that they map to at compilation time:

Table 1. Supported Spring Annotations
Spring Annotation Target Annotation Notes

@Component

@Bean

Example @Component("myBean"). Requires micronaut-context dependency.

@Service

@Bean

Example @Service("myBean"). Requires micronaut-context dependency.

@Repository

@Bean

Example @Repository("myBean"). Requires micronaut-context dependency.

@Autowired

@javax.inject.Inject

Example @Autowired. required=false adds @Nullable

@Value

@Value

Example @Value("${foo.bar}")

@Qualifier

@javax.inject.Named

Example @Qualifier("myBean")

@Configuration

@Factory

Example @Configuration

@Profile

@Requires(env="test")

Example @Profile("test")

@Bean

@Bean

Example @Bean. Requires micronaut-context dependency.

@Import

@Import

Example @Import(MyConfiguration.class). Requires micronaut-context dependency.

@Primary

@Primary

Example @Primary. Requires micronaut-context dependency.

@EventListener

@EventListener

Example @EventListener. Requires micronaut-inject dependency.

@Async

@Async

Example @Async. Requires micronaut-context dependency.

@Scheduled

@Scheduled

Example @Scheduled. Requires micronaut-context dependency.

@Transactional

TransactionInterceptor

Example @Transactional. Requires micronaut-spring dependency.

@Cacheable

@Cacheable

Requires micronaut-runtime and configured cache. Only cacheNames member supported.

@CacheEvict

@CacheInvalidate

Requires micronaut-runtime and configured cache. Only cacheNames member supported.

@CachePut

@CachePut

Requires micronaut-runtime and configured cache. Only cacheNames member supported.

3.3 Supported Spring Data Annotations

Micronaut Data supports Spring Data annotations. To use them add the following dependency:

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

The following table summarizes the Spring Data annotations that Micronaut Data supports and the Micronaut annotation that they map to at compilation time:

Table 1. Supported Spring Data Annotations
Spring Data Annotation Micronaut Data Annotation Notes

@CreatedDate

@DateCreated

Example @CreatedDate private long createdDate.

@Id

@Id

Example @Id private long id.

@LastModifiedDate

@DateUpdated

Example @LastModifiedDate private long modifiedDate.

@PersistenceConstructor

@Creator

Example @PersistenceConstructor public User(String name, Integer age).

@Persistent

@MappedEntity

Example @Persistent public class User.

@Repository

@Repository

Example @Repository interface PersonRepository extends CrudRepository.

@TransactionalEventListener

@TransactionalEventListener

Example @TransactionalEventListener public void handleEvent(MyEvent event).

@Transactional

@Transactional

Example @Transactional @Service public class MyService.

@Transient

@Transient

Example @Transient private String ssn.

@Version

@Version

Example @Version private long version.

See the guide for Micronaut Data from a Spring Boot Application to learn more.

3.4 Supported Spring Interfaces

The following Spring interfaces are supported and can be injected into any bean:

Table 1. Supported Injectable Interfaces

Spring Interface

Adapted Target

Description

Environment

Environment

The Application Environment

ConversionService

ConversionService

For Converting Types

ApplicationEventPublisher

ApplicationEventPublisher

For Publishing Events

ApplicationContext

ApplicationContext

The application context

BeanFactory

BeanContext

The bean context

For compatibility the following Aware interfaces are supported:

Table 2. Supported Aware Interfaces

Spring Interface

Description

EnvironmentAware

For looking up the Environment (but prefer @Autowired)

ApplicationContextAware

For looking up the ApplicationContext (but prefer @Autowired)

BeanFactoryAware

For looking up the BeanFactory (but prefer @Autowired)

3.5 Supported Spring Events

For compatibility the following ApplicationEvent instances are supported:

Table 1. Supported Spring Events

Spring Event

Description

ContextStartedEvent

Fired when the application context is started

ContextClosedEvent

Fired when the application context is shut down

You can write methods annotated with @EventListener to receive the events in either framework.

3.6 Writing Spring MVC Controllers

You can write Spring MVC controllers that are computed into Micronaut controllers at compilation time. The programming model is largely compatible with Spring Web Reactive.

See the example project that is part of the guide Run a Spring Boot Application as a Micronaut Application for an example Spring Web Reactive applications transformed into a Micronaut application.

Only @RestController semantics are supported, which is fine for most Microservice use cases. Special support is provided by the micronaut-spring-web dependency to allowing returning a ResponseEntity.

See the Example application for a demonstration on how to build a Spring MVC application computable to Micronaut.

The binding semantics as described in the Micronaut documentation and are generally equivalent to how Spring MVC behaves.

The following additional, Spring specific, method argument types are supported:

Table 1. Supported Method Argument Types
Type Notes

ServerHttpRequest

For receiving the whole reactive request

java.security.Principal

Requires the micronaut-security module

HttpMethod

The HTTP method

ModelMap, Model

With micronaut-views module. See Server Side View Rendering.

The following return types are supported:

Table 2. Supported Return Types
Type Notes

HttpEntity, ResponseEntity

For customizing the response

HttpHeaders

For sending back only headers

java.lang.String

A view name when combined with Model

Any reactive or POJO return type

Computed to appropriate JSON response

The following Spring MVC annotations are supported:

Table 3. Supported Spring MVC Annotations
Spring Annotation Target Annotation Notes

@RestController

@Controller

Example @RestController

@RequestMapping

@UriMapping

Example: @RequestMapping("/foo/bar")

@GetMapping

@Get

Example: @GetMapping("/foo/bar")

@PostMapping

@Post

Example: @PostMapping("/foo/bar")

@DeleteMapping

@Delete

Example: @DeleteMapping("/foo/bar")

@PatchMapping

@Patch

Example: @PatchMapping("/foo/bar")

@PutMapping

@Put

Example: @PutMapping("/foo/bar")

@RequestHeader

@Header

Example: @RequestHeader("Accept")

@RequestAttribute

No equivalent

Example: @RequestAttribute("Accept")

@RequestBody

@Body

Example: @RequestBody

@RequestPart

@Part

Example: @RequestPart("my-part)

@RequestParam

@QueryValue

Example: @RequestParam("myParam")

@ResponseStatus

@Status

Example: @ResponseStatus(value=HttpStatus.NOT_FOUND)

@ExceptionHandler

@Error

Example: @ExceptionHandler

@CookieValue

@CookieValue

Example: @CookieValue("myCookie")

3.7 Supported Spring Boot Annotations

The following Spring Boot specific annotations are supported:

Table 1. Supported Spring Boot Annotations
Spring Boot Annotation Target Annotation Notes

@ConfigurationProperties

@ConfigurationProperties

Example @ConfigurationProperties("foo.bar")

@ConditionalOnBean

@Requires

Maps to @Requires(beans=Foo.class)

@ConditionalOnClass

@Requires

Maps to @Requires(classes=Foo.class)

@ConditionalOnMissingBean

@Requires

Maps to @Requires(missingBeans=Foo.class)

@ConditionalOnMissingClass

@Requires

Maps to @Requires(missing=Foo.class)

@ConditionalOnNotWebApplication

@Requires

Maps to @Requires(missingBeans=EmbeddedServer.class)

@ConditionalOnProperty

@Requires

Maps to @Requires(property="foo.bar")

@ConditionalOnSingleCandidate

@RequiresSingleCandidateCondition

Maps to @RequiresSingleCandidateCondition(Foo.class)

@ConditionalOnWebApplication

@Requires

Maps to @Requires(beans=EmbeddedServer.class)

With support for @Configuration and the majority of Spring Boot conditions it is possible to build auto configurations that work with both Spring Boot and Micronaut.

In addition, the following Spring Boot Actuator annotations are supported:

Table 2. Supported Spring Boot Actuator Annotations
Spring Actuator Boot Annotation Target Annotation Notes

@Endpoint

@Endpoint

Example @Endpoint("features")

@ReadOperation

@Read

Example @ReadOperation

@WriteOperation

@Write

Example @WriteOperation

@DeleteOperation

@Delete

Example @DeleteOperation

@Selector

@Selector

Example @Selector

What this enables is the ability to write management endpoints that work with both Spring Boot and Micronaut.

3.8 Unsupported Spring Features

As mentioned previously only a subset of Spring is implementated, but enough to build real applications. The question you have to ask yourself coming from Spring is how much Spring do you need?

The following notable features are currently not supported in Micronaut for Spring either and in general if a feature is not documented here consider it unsupported:

  • AspectJ - Spring’s AOP implementation is not supported, you can however use Micronaut AOP which is compilation time and reflection free.

  • Spring Expression Language (SpEL) - SpEL expressions are not supported, property placeholders are, however.

  • The Servlet API - Any reference to the Servlet API is not supported

3.9 Using Micronaut's HTTP Client

Since annotations values are mapped at compilation time, this also impacts the authoring of Micronaut’s compile-time declarative HTTP client.

You can essentially use Spring annotations to a defined a compilation-time HTTP client:

Spring @Client Implementation
/*
 * Copyright 2017-2019 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.spring.web.annotation;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Header;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.http.client.multipart.MultipartBody;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@Client("/")
public interface GreetingClient {

    @GetMapping("/")
    String home();

    @PostMapping("/request")
    @Header(name = "Foo", value = "Bar")
    Greeting requestTest(@RequestBody Greeting greeting);

    @GetMapping("/greeting{?name}")
    Greeting greet(@Nullable String name);

    @PostMapping("/greeting")
    Greeting greetByPost(@RequestBody Greeting greeting);

    @DeleteMapping("/greeting")
    HttpResponse<?> deletePost();

    @GetMapping("/nested/greeting{?name}")
    Greeting nestedGreet(@Nullable String name);

    @GetMapping("/greeting-status{?name}")
    HttpResponse<Greeting> greetWithStatus(@Nullable String name);

    @PostMapping(value = "/multipart-request", consumes = MediaType.TEXT_PLAIN_VALUE, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
    String multipartRequest(@RequestBody MultipartBody body);
}

This also means you can define a common interface between client and server of a Spring application and compute the client at compilation name.

if you are using low-level HTTP clients see the guide for Building URIs - Spring Boot to Micronaut Framework that compares Spring’s UriComponentsBuilder to Micronaut Framework’s UriBuilder.

4 Sharing Libraries between Spring and Micronaut

If you have a lot of existing Spring applications it may be useful to share libraries between Micronaut and Spring.

This is a common requirement if you want to say share common injectable components that can be added to classpath.

If you have this use case you can resolve it by using Spring annotations to define the components using annotations like @configuration, @component and @bean.

For example:

Example Spring Configuration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MyConfiguration {

    @Bean
    @Primary
    public MyBean myBean() {
        return new MyBean("default");
    }


    @Bean("another")
    public MyBean anotherBean() {
        return new MyBean("another");
    }


    public static class MyBean {
        private final String name;

        MyBean(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}

The above configuration, which exposes a bean of type MyBean, can be imported and used by any Spring application using the @import annotation declared as follows:

Using @Import
import org.springframework.context.annotation.Import;

@Import(MyConfiguration.class)
class Application {}

You can additionally use the same configuration in a Micronaut application by use the same declaration as above assuming you have correctly configured Micronaut for Spring. See the example project that is part of the guide Run a Spring Boot Application as a Micronaut Application for how to configure Micronaut for Spring.

Micronaut will import all declared beans at compilation time. The only limitation is that ImportBeanDefinitionRegistrar that require runtime interfaces like BeanClassLoaderAware will fail to import with a compilation error since import processing happens during compilation with Micronaut. When creating shared components try to avoid defining ImportBeanDefinitionRegistrar types that depend on one of the following interfaces:

  • BeanClassLoaderAware

  • BeanFactoryAware

  • EnvironmentAware

  • ResourceLoaderAware

5 Using Micronaut Modules with Spring

It may be desirable to use Micronaut modules or libraries from a Spring or Spring Boot application. For example, you may wish to use the Micronaut HTTP Client or Micronaut Data within your Spring application. There are several ways you can integrate Micronaut into a Spring application which are described below.

5.1 Using the Micronaut Spring Boot Starter

The easiest way to use Micronaut inside Spring is to use the Micronaut Spring Boot starter, first include the Micronaut BOM in your Spring Boot application’s build configuration for Gradle:

Adding the Micronaut BOM to Gradle
implementation platform("io.micronaut.platform:micronaut-platform:4.0.0")
annotationProcessor platform("io.micronaut.platform:micronaut-platform:4.0.0")

or Maven:

Adding the Micronaut BOM to Maven
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.micronaut.platform</groupId>
            <artifactId>micronaut-platform</artifactId>
            <version>4.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
if you prefer not to import the BOM that is also possible, but note you will have to declare dependency versions explicitly.

Then add the Micronaut annotation processor to your build configuration:

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

You will then need to explicitly specify a dependency on a version of the Jakarta Annotations module that uses the jakarta namespace instead of the javax namespace (versions 2.0.x and above). This is because the Spring Boot BOM automatically downgrades this module’s version to one that uses the javax namespace which is incompatible with Micronaut:

annotationProcessor("jakarta.annotation:jakarta.annotation-api:2.1.1")
<annotationProcessorPaths>
    <path>
        <groupId>jakarta.annotation</groupId>
        <artifactId>jakarta.annotation-api</artifactId>
        <version>2.1.1</version>
    </path>
</annotationProcessorPaths>

implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

Finally, a dependency on micronaut-spring-boot-starter can be added to the build:

implementation("io.micronaut.spring:micronaut-spring-boot-starter")
<dependency>
    <groupId>io.micronaut.spring</groupId>
    <artifactId>micronaut-spring-boot-starter</artifactId>
</dependency>

When the Spring Boot application starts app all beans provided by Micronaut will be exposed as Spring Beans as well.

You can control which beans are exposed to Spring by using the @EnableMicronaut annotation on your Application class and specifying a MicronautBeanFilter to include or exclude beans from Micronaut.

Using Micronaut Data

Micronaut Data can be used by adding the Micronaut Data annotation processor:

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

And module you are interested in, for example Micronaut Data JDBC:

implementation("io.micronaut.data:micronaut-data-jdbc")
<dependency>
    <groupId>io.micronaut.data</groupId>
    <artifactId>micronaut-data-jdbc</artifactId>
</dependency>

However, it is important to note that you will once again need to specify a version of the Jakarta Persistence API that uses the jakarta namespace instead of the javax namespace as the Spring Boot BOM forces these to older versions in Spring Boot 2.x:

annotationProcessor("jakarta.persistence:jakarta.persistence-api:3.1.0")
<annotationProcessorPaths>
    <path>
        <groupId>jakarta.persistence</groupId>
        <artifactId>jakarta.persistence-api</artifactId>
        <version>3.1.0</version>
    </path>
</annotationProcessorPaths>

implementation("jakarta.persistence:jakarta.persistence-api:3.1.0")
<dependency>
    <groupId>jakarta.persistence</groupId>
    <artifactId>jakarta.persistence-api</artifactId>
    <version>3.1.0</version>
</dependency>

5.2 Using Micronaut Parent Context

You can also use Micronaut for Spring as the parent application context to a regular Spring application.

This has a number of benefits, you can for example define beans using Micronaut and consume any Micronaut beans into a Spring application, resulting in Spring using less memory and having reflection free infrastructure.

You can also use any Micronaut feature from a regular Spring Boot or Spring application including the declaring clients for HTTP and Kafka.

You can also use any compilation time tools from Micronaut with Spring such as Micronaut’s support for Swagger.

The following example shows how to Configure your Spring Boot application with a Micronaut powered parent application context using SpringApplicationBuilder:

Using the Micronaut Parent Context
var builder = new SpringApplicationBuilder();
var context = new MicronautApplicationContext();
context.start();
builder.parent(context)
    .sources(Application.class)
    .build()
    .run();

5.3 Using a Bean Post Processor

The MicronautBeanProcessor class is a BeanFactoryPostProcessor which will add Micronaut beans to a Spring Application Context. An instance of MicronautBeanProcessor should be added to the Spring Application Context. MicronautBeanProcessor requires a constructor parameter which represents a list of the types of Micronaut beans which should be added to the Spring Application Context. The processor may be used in any Spring application. As an example, a Grails 3 application could take advantage of MicronautBeanProcessor to add all the Micronaut HTTP Client beans to the Spring Application Context with something like the folowing:

// grails-app/conf/spring/resources.groovy
import io.micronaut.spring.beans.MicronautBeanProcessor
import io.micronaut.http.client.annotation.Client

beans = {
    httpClientBeanProcessor MicronautBeanProcessor, Client
}

Multiple types may be specified:

// grails-app/conf/spring/resources.groovy
import io.micronaut.spring.beans.MicronautBeanProcessor
import io.micronaut.http.client.annotation.Client
import com.sample.Widget

beans = {
    httpClientBeanProcessor MicronautBeanProcessor, [Client, Widget]
}

In a non-Grails application something similar may be specified using any of Spring’s bean definition styles:

@Configuration
class ByAnnotationTypeConfig {

    @Bean
    MicronautBeanProcessor beanProcessor() {
        new MicronautBeanProcessor(Prototype, Singleton)
    }
}

6 Guides

See the following list of guides to learn more about working with Spring in the Micronaut Framework:

7 Repository

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