[JAVA] Try DI with Micronaut

DI with Micronaut

Micronaut seems to have a DI (Dependency Injection) mechanism.

Inversion of Control

As a feature,

There seems to be something like that.

Scope used in Micronaut DI

Micronaut uses JSR-330 for annotation.

https://docs.oracle.com/javaee/6/api/javax/inject/package-summary.html

In addition to the @ Singleton included in JSR-330, click here for the scope annotation used by Micronaut.

Scopes

There are some strange things.

The @ Context scope represents a bean that needs to be initialized and shut down when the BeanContext starts and ends.

Micronaut seems to lazy initialize a Singleton bean, so you can use the @Context annotation to initialize it when the BeanContext starts. That said, Micronaut is designed to create a minimal number of beans at startup, so the @Context spec seems to be conservative.

There are some strange things like @ThreadLocal. @ Infrastructure seems to be a stereotype of @ Singleton.

There is also a refreshable scope called @Refreshable, and it seems that you can refresh with the / refresh endpoint or RefreshEvent.

Refreshable Scope

Click here for packages with annotations around here.

https://docs.micronaut.io/1.0.4/api/io/micronaut/context/annotation/package-summary.html

However, the @Controller annotation that appears in Quick Start is also a kind of scope annotation. It seems that this is not the only thing in total ...

Click here for DI-enabled container types (such as ʻOptional and ʻIterable).

Injectable Container Types

There seems to be Qualifiers as well.

Bean Qualifiers

Let's touch it a little easier.

environment

Click here for this environment.

$ mn -V
| Micronaut Version: 1.0.4
| JVM Version: 1.8.0_191

Create a template for your application.

$ mn create-app hello-di --build maven
$ cd hello-di

Sample application

Let's write a simple sample using the @ Singleton and @ Prototype scopes.

@Singleton Service.

src/main/java/hello/di/service/SingletonService.java

package hello.di.service;

import javax.inject.Singleton;

@Singleton
public class SingletonService {
    public String message() {
        return "Hello Singleton Bean";
    }
}

Use this Service, Controller.

src/main/java/hello/di/controller/SingletonBeanController.java

package hello.di.controller;

import hello.di.service.SingletonService;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/singleton")
public class SingletonBeanController {
    SingletonService singletonService;

    public SingletonBeanController(SingletonService singletonService) {
        this.singletonService = singletonService;
    }

    @Get(produces = MediaType.TEXT_PLAIN)
    public String index() {
        return singletonService.message() + " from " + singletonService.getClass().getName() + "@" + singletonService.hashCode();
    }
}

It seems that constructor injection is possible.

    SingletonService singletonService;

    public SingletonBeanController(SingletonService singletonService) {
        this.singletonService = singletonService;
    }

Also, try issuing a hash code to confirm that the instances are the same.

    @Get(produces = MediaType.TEXT_PLAIN)
    public String index() {
        return singletonService.message() + " from " + singletonService.getClass().getName() + "@" + singletonService.hashCode();
    }

Next, a Service that is @ Prototype.

src/main/java/hello/di/service/PrototypeService.java

package hello.di.service;

import io.micronaut.context.annotation.Prototype;

@Prototype
public class PrototypeService {
    public String message() {
        return "Hello Prototype Bean";
    }

}

Use this Service, Controller.

src/main/java/hello/di/controller/PrototypeBeanController.java

package hello.di.controller;

import javax.inject.Inject;

import hello.di.service.PrototypeService;
import io.micronaut.context.ApplicationContext;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/prototype")
public class PrototypeBeanController {
    @Inject
    ApplicationContext applicationContext;

    @Get(produces = MediaType.TEXT_PLAIN)
    public String index() {
        PrototypeService prototypeService = applicationContext.getBean(PrototypeService.class);
        return prototypeService.message() + " from " + prototypeService.getClass().getName() + "@" + prototypeService.hashCode();
    }
}

Controller seems to be Singleton, and when I injected it as it is, it became the same instance even though it was @ Prototype, so I decided to get it from ʻApplicatoinContext` ...

    @Get(produces = MediaType.TEXT_PLAIN)
    public String index() {
        PrototypeService prototypeService = applicationContext.getBean(PrototypeService.class);
        return prototypeService.message() + " from " + prototypeService.getClass().getName() + "@" + prototypeService.hashCode();
    }

Is it because there is no client proxy?

Also, it seems that you can use the @Inject annotation.

    @Inject
    ApplicationContext applicationContext;

ʻApplicationContext` constructor injection is also OK.

    PrototypeService prototypeService;

    public PrototypeBeanController(PrototypeService prototypeService) {
        this.prototypeService = prototypeService;
    }

The class with the main method is omitted because it is still automatically generated.

Verification

Access Controller using @Singleton Service.

$ curl localhost:8080/singleton
Hello Singleton Bean from hello.di.service.SingletonService@56609473


$ curl localhost:8080/singleton
Hello Singleton Bean from hello.di.service.SingletonService@56609473


$ curl localhost:8080/singleton
Hello Singleton Bean from hello.di.service.SingletonService@56609473

I was able to confirm that the DI was working and the same Service was returned.

Then, @ Prototype.

$ curl localhost:8080/prototype
Hello Prototype Bean from hello.di.service.PrototypeService@1219715735


$ curl localhost:8080/prototype
Hello Prototype Bean from hello.di.service.PrototypeService@1284304729


$ curl localhost:8080/prototype
Hello Prototype Bean from hello.di.service.PrototypeService@1807347832

Here you can see that the Service of a different instance is returned.

Automatically generated file

By the way, what kind of file was generated by Annotation Processor?

$ tree target
target
├── classes
│   ├── META-INF
│   │   ├── hello-di.kotlin_module
│   │   └── services
│   │       └── io.micronaut.inject.BeanDefinitionReference
│   ├── application.yml
│   ├── hello
│   │   └── di
│   │       ├── Application.class
│   │       ├── controller
│   │       │   ├── $PrototypeBeanControllerDefinition$$exec1$$AnnotationMetadata.class
│   │       │   ├── $PrototypeBeanControllerDefinition$$exec1.class
│   │       │   ├── $PrototypeBeanControllerDefinition.class
│   │       │   ├── $PrototypeBeanControllerDefinitionClass$$AnnotationMetadata.class
│   │       │   ├── $PrototypeBeanControllerDefinitionClass.class
│   │       │   ├── $SingletonBeanControllerDefinition$$exec1$$AnnotationMetadata.class
│   │       │   ├── $SingletonBeanControllerDefinition$$exec1.class
│   │       │   ├── $SingletonBeanControllerDefinition.class
│   │       │   ├── $SingletonBeanControllerDefinitionClass$$AnnotationMetadata.class
│   │       │   ├── $SingletonBeanControllerDefinitionClass.class
│   │       │   ├── PrototypeBeanController.class
│   │       │   └── SingletonBeanController.class
│   │       └── service
│   │           ├── $PrototypeServiceDefinition.class
│   │           ├── $PrototypeServiceDefinitionClass$$AnnotationMetadata.class
│   │           ├── $PrototypeServiceDefinitionClass.class
│   │           ├── $SingletonServiceDefinition.class
│   │           ├── $SingletonServiceDefinitionClass$$AnnotationMetadata.class
│   │           ├── $SingletonServiceDefinitionClass.class
│   │           ├── PrototypeService.class
│   │           └── SingletonService.class
│   └── logback.xml
└── generated-sources
    └── annotations

9 directories, 25 files

Somehow, various things are made.

It seems that a file for the service provider has been created, so the contents here as well.

target/classes/META-INF/services/io.micronaut.inject.BeanDefinitionReference

hello.di.service.$PrototypeServiceDefinitionClass
hello.di.service.$SingletonServiceDefinitionClass
hello.di.controller.$SingletonBeanControllerDefinitionClass
hello.di.controller.$PrototypeBeanControllerDefinitionClass

For the time being, I was able to confirm the atmosphere.

Recommended Posts

Try DI with Micronaut
Try create with Trailblazer
Try WebSocket with jooby
Try WildFly with Docker
Hello World with Micronaut
Serverless Function with Micronaut
Try using DI container with Laravel and Spring Boot
I tried DI with Ruby
Try using GloVe with Deeplearning4j
Try using view_component with rails
Try DB connection with Java
Try gRPC with Java, Maven
Access Apache Kafka with Micronaut
Try reading XML with JDOM
Write a Reactive server with Micronaut
Try running cloudera manager with docker
Try implementing recaptcha with Jetty embedded.
Try manipulating PostgreSQL arrays with JDBC
Try using Redis with Java (jar)
Add Bean Validation with Micronaut (Java)
Try to imitate marshmallows with MiniMagick
Try parsing English with Stanford CoreNLP
Try bidirectional communication with gRPC Java
Try running MySql and Blazor with docker-compose
Let's try WebSocket with Java and javascript!
Try running Slack's (Classic) Bot with docker
Try using Spring Boot with VS Code
Try shaking your hands with ARKit + Metal
Try to implement login function with Spring-Boot
Try managing Java libraries with AWS CodeArtifact
Try using Kong + Konga with Docker Compose.
Try with resources statement in web app
Try using the Wii remote with Java
Try creating an iOS library with CocoaPods