Micronaut for Spring

Extensions to integrate Micronaut and Spring

Version: 1.0.1

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.

Release Notes

1.0.0.RC1

  • Bug fixes

  • Support for ApplicationRunner interface in Spring Boot

1.0.0.M2

  • Examples for Maven and Kotlin to examples directory

  • @Profile("test") now mapped to @Requires(env="test")

  • Better support for registerSingleton

2 Compile Time Spring Annotation Support

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

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.

2.1 Build Configuration

Micronaut 1.0.1 or above is required and the following is a minimal build to get this working for Spring (a non-web application):

plugins {
    id "java"
    id "org.springframework.boot" version "2.1.0.RELEASE"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
    id "net.ltgt.apt" version "0.19"                    // for Java and Groovy applications
    id "org.jetbrains.kotlin:kapt" version "1.2.61"     // for Kotlin applications
}

dependencies {
    // for Java applications
    annotationProcessor "io.micronaut:micronaut-inject-java:1.0.4"
    annotationProcessor "io.micronaut:micronaut-validation:1.0.4"
    annotationProcessor "io.micronaut.spring:micronaut-spring-annotation:1.0.1"

    // for Kotlin applications
    kapt "io.micronaut:micronaut-inject-java:1.0.4"
    kapt "io.micronaut:micronaut-validation:1.0.4"
    kapt "io.micronaut.spring:micronaut-spring-annotation:1.0.1"

    // for Groovy applications
    compileOnly "io.micronaut:micronaut-inject-groovy:$micronautVersion"
    compileOnly "io.micronaut:micronaut-validation:$micronautVersion"
    compileOnly "io.micronaut.spring:micronaut-spring-annotation:$micronautSpringVersion"

    compile "io.micronaut:micronaut-inject:1.0.4"
    compile("org.springframework.boot:spring-boot-starter")
    ...
}
If you are only going to reference Spring annotations and not Spring classes or interfaces then org.springframework.boot:spring-boot-starter can be compileOnly

2.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-runtime dependency.

@Service

@Bean

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

@Repository

@Bean

Example @Repository("myBean"). Requires micronaut-runtime 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-runtime dependency.

@Primary

@Primary

Example @Primary. Requires micronaut-runtime dependency.

@EventListener

@EventListener

Example @EventListener. Requires micronaut-inject dependency.

@Async

@Async

Example @Async. Requires micronaut-runtime dependency.

@Scheduled

@Scheduled

Example @Scheduled. Requires micronaut-runtime dependency.

@Transactional

@Transactional

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.

2.3 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)

2.4 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.

2.5 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.

To get started you should modify your dependencies as following:

Including spring-web processing
dependencies {

    ...
    // additional Spring web dependencies
    annotationProcessor "io.micronaut.spring:micronaut-spring-web-annotation:1.0.1"
    compile("org.springframework.boot:spring-boot-starter-web")


    // additional web dependencies for Micronaut
    compile("io.micronaut:micronaut-http-server:1.0.4")
    runtime("io.micronaut.spring:micronaut-spring-web:1.0.1")
    runtime("io.micronaut:micronaut-http-server-netty:1.0.4")

}

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

@RequestParam

@QueryValue

Example: @RequestParam("myParam")

@ResponseStatus

@Status

Example: @ResponseStatus(value=HttpStatus.NOT_FOUND)

@ExceptionHandler

@Error

Example: @ExceptionHandler

@CookieValue

@CookieValue

Example: @CookieValue("myCookie")

2.6 Supported Spring Boot Annotations

For additional support for Spring Boot you should add the following dependencies:

Including spring-boot processing
dependencies {

    ...
    // additional Spring Boot dependencies
    annotationProcessor "io.micronaut.spring:micronaut-spring-boot:1.0.1"
    compile("org.springframework.boot:spring-boot-starter-web")

    // additional Spring Boot dependencies for Micronaut
    runtime("io.micronaut.spring:micronaut-spring-boot:1.0.1")
}

With the above dependencies in place 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.

2.7 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

2.8 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 define 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.http.HttpResponse;
import io.micronaut.http.annotation.Header;
import io.micronaut.http.client.annotation.Client;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Nullable;

@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);
}

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

3 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
SpringApplicationBuilder builder = new SpringApplicationBuilder();
MicronautApplicationContext context = new MicronautApplicationContext();
context.start();
builder.parent(context);
builder.sources(Application);
builder.build().application.run();