Monday, 16 January 2023

Eager initialization of Singleton beans in Micronaut application

@Singleton-scoped beans are created lazily and on-demand by default.

 

If you want to initialize these beans eagerly,

a.    you can go with @Parallel annotation, which allows parallel initialization of your bean without impacting overall startup time. You can find this example in my previous post.

b.   Using ‘eagerInitSingletons’ method of ApplicationContextBuilder interface.

 

Micronaut.build(args)

  .eagerInitSingletons(true)

  .mainClass(App.class)

  .start();

 

Find the below working application.

 

Step 1: Create new maven project ‘micronaut-eager-init-of-beans’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sample.app</groupId>
  <artifactId>micronaut-eager-init-of-beans</artifactId>
  <version>1</version>

  <parent>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-parent</artifactId>
    <version>3.7.0</version>
  </parent>

  <properties>
    <packaging>jar</packaging>
    <jdk.version>11</jdk.version>
    <release.version>11</release.version>
    <micronaut.version>3.7.0</micronaut.version>
    <micronaut.runtime>netty</micronaut.runtime>
    <exec.mainClass>com.sample.app.App</exec.mainClass>
  </properties>

  <repositories>
    <repository>
      <id>central</id>
      <url>https://repo.maven.apache.org/maven2</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-inject</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-validation</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-http-client</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-http-server-netty</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut</groupId>
      <artifactId>micronaut-jackson-databind</artifactId>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.micronaut.test</groupId>
      <artifactId>micronaut-test-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>io.micronaut.build</groupId>
        <artifactId>micronaut-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

 

Step 3: Define DemoBean class.

 

DemoBean.java
package com.sample.app.model;

import java.util.concurrent.atomic.AtomicInteger;

public class DemoBean {
  private static AtomicInteger counter = new AtomicInteger(1);

  private int id;

  private String description;

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public DemoBean() {
    System.out.println("DemoBean default constructor called for ");
  }

  public DemoBean(String description) {
    this.description = description;
    this.id = counter.getAndIncrement();
    System.out.println("DemoBean constructor called for " + description);
  }

  @Override
  public String toString() {
    int identityHashCode = System.identityHashCode(this);

    return "DemoBean [id=" + id + ", description=" + description + ", identityHashCode= " + identityHashCode + "]";
  }

}

Step 4: Define BeansFactory class.

 

BeansFactory.java

package com.sample.app.factory;

import com.sample.app.model.DemoBean;

import io.micronaut.context.annotation.Factory;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

@Factory
public class BeansFactory {

  @Singleton
  @Named("mySingletonBean1")
  public DemoBean singletonBean1() {
    DemoBean bean = new DemoBean("singletonBean1");
    return bean;
  }

  @Singleton
  @Named("mySingletonBean2")
  public DemoBean singletonBean2() {
    DemoBean bean = new DemoBean("singletonBean2");
    return bean;
  }

  @Singleton
  @Named("mySingletonBean3")
  public DemoBean singletonBean3() {
    DemoBean bean = new DemoBean("singletonBean3");
    return bean;
  }

}

Step 5: Define HelloWorldController class.

 

HelloWorldController.java

package com.sample.app.controller;

import com.sample.app.model.DemoBean;

import io.micronaut.context.ApplicationContext;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.inject.qualifiers.Qualifiers;
import jakarta.inject.Inject;

@Controller
public class HelloWorldController {

  @Inject
  private ApplicationContext applicationContext;

  private String output() {
    DemoBean mySingletonBean1 = applicationContext.getBean(DemoBean.class, Qualifiers.byName("mySingletonBean1"));
    DemoBean mySingletonBean2 = applicationContext.getBean(DemoBean.class, Qualifiers.byName("mySingletonBean2"));
    DemoBean mySingletonBean3 = applicationContext.getBean(DemoBean.class, Qualifiers.byName("mySingletonBean3"));

    StringBuilder builder = new StringBuilder();
    builder.append(mySingletonBean1).append("\n");
    builder.append(mySingletonBean2).append("\n");
    builder.append(mySingletonBean3).append("\n");

    return builder.toString();
  }

  @Get(value = "/hello", produces = MediaType.TEXT_PLAIN)
  public String index() {

    return output();
  }

}

Step 6: Define main application class.

 

App.java

package com.sample.app;

import io.micronaut.runtime.Micronaut;

public class App {
  public static void main(String[] args) {
     Micronaut.build(args)
         .eagerInitSingletons(true) 
         .mainClass(App.class)
         .start();
  }
}

Total project structure looks like below.




Build the project using mvn package command.

Navigate to the folder where pom.xml is located and execute the command ‘mvn package’.

 

Upon command successful execution, you can see the jar file ‘micronaut-eager-init-of-beans-1.jar’ in project target folder.

$ ls ./target/
classes           maven-status
generated-sources       micronaut-eager-init-of-beans-1.jar
generated-test-sources        original-micronaut-eager-init-of-beans-1.jar
maven-archiver          test-classes

Execute below command to run the application.

java -jar ./target/micronaut-eager-init-of-beans-1.jar

You will see below messages in the console.

DemoBean constructor called for singletonBean1
DemoBean constructor called for singletonBean2
DemoBean constructor called for singletonBean3

You can download this application from this link.


 

Previous                                                    Next                                                    Home

No comments:

Post a Comment