Execution Order of @PostConstruct

Viewed 12045

I have 2 singletons in my JEE application that I want to initialize at start up. Something like this:

@Singleton
@Startup
public class ServiceB {

    @EJB
    private ServiceA a;

    @PostConstruct
    private void init() {
        ....
    }
}

ServiceB doesn't really need ServiceA, I just added the dependency to make sure that ServiceA is fully initialized (read: @PostConstruct-method finished) before ServiceB's init() -Method starts.

But it doesn't wait. ServiceB actually starts before ServiceA.

Is there any way to ensure that one Bean's @PostConstruct- method waits for another Bean's @PostConstruct-method to finish?

I know I could just remove the @PostConstruct Annotation in ServiceA and call it directly from ServiceB

    @PostConstruct init() {
        a.init();
    }

but I have deployments where there is no ServiceB. So I can't rely on ServiceB to init ServiceA. ServiceA has to do that itself. And ServiceB must wait for ServiceA to be done with it.

4 Answers

Use the @DependsOn annotation to declare an initialization dependency on startup beans.

Example:

@Singleton
@Startup
public class ServiceA {
    @PostConstruct
    public void init() { ... }
}

@Singleton
@Startup
@DependsOn("ServiceA")
public class ServiceB {
    @EJB
    ServiceA a;

    @PostConstruct
    public void init() { ... } // will be called after a is initialized
}

A question on the answer given by @DmiN (I am new user so not able to post a comment directly)

With your suggestion (as shown in code below) -- I agree that Service B will start after Service A is initialized (just initialized, not that postconstruct is complete). But I doubt if it can be guaranteed that ServiceB's init method will never run unless the Service A's PostConstruct method has finished execution? Correct?

@Singleton
@Startup
public class ServiceA {
    @PostConstruct
    public void init() { ... }
}

@Singleton
@Startup
@DependsOn("ServiceA")
public class ServiceB {
    @EJB
    ServiceA a;

    @PostConstruct
    public void init() { ... } // will be called after a is initialized
}

The @PostConstruct annotation is used for methods executed after dependency injection is complete, So here the injection of service A in service B is done, then the init function of Service B can be executed

public class ServiceA {

@PostConstruct
public void init() { }

}


public class ServiceB {

@Autowired
ServiceA a;

@PostConstruct
public void init() { }
}

As a simple alternative solution, you can manually collect all your independent beans that should be inited in a defined order in one place. It helps to avoid @DependsOn

public interface OrderedPostConstruct {
    void init();
}

// ==== Production ====
@Configuration
public class InitConfig {

    private final ObjectProvider<OrderedPostConstruct> initializers;

    @PostConstruct
    public void initEntryPoint() {
        initializers.orderedStream().forEach(Initialize::init);
    }
}

@Order(1)
@Component
public class OneUsefullComponent implements OrderedPostConstruct {
    @Override
    public void init() {
        // executed first
    }
}

@Order(2)
@Component
public class TwoUsefullComponent implements OrderedPostConstruct {
    @Override
    public void init() {
        // executed second
    }
}

// ==== Integration tests ====
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class TestDataPopulator implements OrderedPostConstruct {
    @Override
    public void init() {
        // populate data for tests
    }
}
Related