Search code examples
micronautpostconstruct

@PostConstruct is not invoked by Micronaut when a bean with scope @Context is instantiated in @Factory class


When I create a class annotated with @Context and run a Micronaut application, the @PostConstruct method works.

Example:

package com.example;

import io.micronaut.context.annotation.Context;

import javax.annotation.PostConstruct;

@Context
public class ClassHello1 {

    @PostConstruct
    public void sayHello() {
        System.out.println("Hello from ClassHello1");
    }

    public void doSmth() {
        System.out.println("Doing something...");
    }
}

When I remove @Context annotation from the class ClassHello1 and create a bean with a scope @Context inside @Factory class, @PostConstruct method inside ClassHello1 doesn't work.

Example:

package com.example;

import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Factory;

@Factory
public class FactoryClass {


    @Context
    public ClassHello1 classHello1() {
        return new ClassHello1();
    }
}
-------
package com.example;

import javax.annotation.PostConstruct;

public class ClassHello1 {

    @PostConstruct
    public void sayHello() {
        System.out.println("Hello from ClassHello1");
    }

    public void doSmth() {
        System.out.println("Doing something...");
    }
}

Even if I create another @Context bean and call a method doSmth() of ClassHello1 bean, @PostConstruct in ClassHello1 doesn't work anyway.\

package com.example;

import io.micronaut.context.annotation.Context;
import jakarta.inject.Inject;

import javax.annotation.PostConstruct;

@Context
public class ClassHello2 {

    @Inject
    private ClassHello1 classHello1;

    @PostConstruct
    public void init() {
        classHello1.doSmth();
    }
}

In this example doSmth() method of classHello1 bean is invoked, but annotated with @PostConstruct sayHello() doesn't work.

May you explain to me how can I instantiate ClassHello1 in @Factory class and make its @PostConstruct method work?

Thank you.


Solution

  • public ClassHello1 classHello1() {
            return new ClassHello1(); // <1>
        }
    
    1. Creating the bean with new will not trigger the @PostConstruct

    For example:

    import jakarta.annotation.PostConstruct;
    import jakarta.inject.Singleton; //preferred over javax
    
    @Singleton // only one instance of the bean will exist (lazy initialization)
    // @Prototype // new instance of the bean is created each time it is injected (lazy)
    // @Context // created at the same time as the ApplicationContext (eager)
    public class Hello {
        @PostConstruct
        public void sayHello() {
            System.out.println("Hello World!");
        }
    
        public void doSmth() {
            System.out.println("Doing something...");
        }
    }
    
    @Controller("/hello")
    public class HelloController {
    
        private final Hello hello;
    
        public HelloController(Hello hello) {
            this.hello = hello;
        }
    
        @Get("/injected")
        public String injected() {
            hello.doSmth();
            return "hello.sayHello() was called";
        }
    
        @Get("/instantiated")
        public String instantiated() {
            Hello h = new Hello();
            h.doSmth();
            return "hello.sayHello() was NOT called";
        }
    }