Does annotating a bean @DependsOn mean the dependent bean will be instantiated or initialized?

32,128

In your particular case @PostConstruct method of bean A won't be called until B is fully initialized, ie. all its dependencies are injected and its @PostConstruct finishes executing.

updated: Since you are relying on Spring Lifecycle functionality here, can you implement Lifecycle in A and move your JMS call to start() method there?

Share:
32,128
Admin
Author by

Admin

Updated on January 12, 2020

Comments

  • Admin
    Admin over 4 years

    I am using Spring 3.0.2. I have two relatively simple bean definitions. One has a @PostConstruct (bean 'A') which triggers a chain of events that the @DependsOn bean (bean 'B') needs to be prepared for. However, it seems even though that I stated that the bean 'A' is dependent on bean 'B', the events (the lifecycle methods) of bean 'A' are running before bean 'B' is fully initialized.

    Does stating that a bean is "dependent" via @DependsOn (or for that matter, depends-on in a bean definition) mean that the dependent bean's lifecycle methods will be completed before the bean that is dependent on said bean?

    Will bean 'B' lifecycle methods be completed before bean 'A'?

    UPDATE

    Bean A is a custom class that is using a JMS Template to send a message announcing that he has initialized.

    The recipient of said message processes it and forwards it's configuration to a MessageListeningContainer (Bean B).

    The first part is happening all before Bean B has been started by the DefaultLifecycleProcessor.

    @Component
    @DependsOn("beanB")
    public class BeanA {
        @PostConstruct
        public void init() {
            // do stuff
        }
    }
    
    <bean id="beanB" class="org.springframework.jms.listener.DefaultMessageListenerContainr">
        <!-- other configuration -->
    </bean>
    

    I added in my init method the injection of bean b plus two logging statements:

    container.isRunning();
    container.isActive();
    

    I looked at the spring source and isActive is set to true after the Initialization method (doInitialized is completed). The isRunning is set after the doStart is completed. The doStart is triggered by the DefaultLifecycleProcessor which is occurring after the @PostConstruct annotated methods are called.

    How can I guarantee that my Postconstruct method is called AFTER bean b has been initialized AND started?

  • Admin
    Admin over 12 years
    This seems to be true. I inspected my bean B during the bean A post construct. However, the Bean B not only has a initialization implementation (InitializingBean) but it also implements the LifeCycle interface. It seems as though the LifecycleProcessor is called after beans are initialized. So it seems I need to change my post construct to be a lifecycle phase implementation.
  • Admin
    Admin over 12 years
    Digging further I see that Annotations are processed first, followed by interfaces. This is the true issue. Since Bean B implements the interface, its Lifecycle start method isn't invoked until after the annotated method.
  • mrembisz
    mrembisz over 12 years
    @predhme Maybe using bean dependency mechanism is not the best way to organize asynchronous processing interactions which you seem to be dealing with here. Have you considered separating processing startup from bean initialization and orchestrating it from a dedicated single bean? Still much information is missing here to be really helpful.
  • Admin
    Admin over 12 years
    I updated my class so that it implements the lifecycle interface. The method init I changed to implement the start method. However, this method is never called now. Is this because my bean is a @Component?
  • mrembisz
    mrembisz over 12 years
    @predhme Right, you should use SmartLifecycle instead of Lifecycle and implement isAutoStartup as return true
  • Admin
    Admin over 12 years
    I implemented the SmartLifeCycle and found it to yeild issues with the stop(Runnable) implementation. I later found a ApplicationListener<ContextRefreshedEvent> interface. Works perfectly now. Thanks