June 29, 2022

Spring depends-on Attribute and @DependsOn Annotation

If one bean has a dependency on another bean then generally in Spring framework we configure it to be set as a property of another. Typically you accomplish this with the <ref/> element in XML-based configuration metadata or using @Autowired annotation. However, sometimes dependencies between beans may not be direct but you may still want to ensure that a specific bean is initialized before another bean. For example in one bean there is a static block which has to be executed before another bean is initialized. In Spring you can use depends-on attribute in XML configuration or @DependsOn annotation to explicitly force one or more beans to be initialized before the bean using this element is initialized.

Spring depends-on attribute example

In the example there is a class ClassB and another class ClassA which has a static block. You want to ensure that ClassA is initialized first and its static block executed before ClassB is initialized even thought ClassB has no direct dependency on ClassA.

public class ClassA {
  ClassA(){
    System.out.println("In constructor of ClassA");
  }
  //static block
  static {
    System.out.println("in static block ClassA");
    System.out.println("Register DB Driver as a one time activity");
  }
}
public class ClassB {
  ClassB(){
    System.out.println("In constructor of ClassB");
  }
}
Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="beanA" class="com.knpcode.springbeans.ClassA" />  
   	
    <bean id="beanB" class="com.knpcode.springbeans.ClassB" depends-on="beanA">  
    </bean>
</beans>

In the configuration there is a bean definition for ClassA and ClassB as you can see there is no direct dependency on beanA in beanB so depends-on attribute is used to enforce that beanA is initialized before beanB.

You can use the following class with main method to read the configuration and access beans.

public class App {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    ClassB obj = context.getBean("beanB", ClassB.class);
    context.close();
  }
}
Output
10:26:02.631 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanA'
in static block ClassA
Register DB Driver as a one time activity
In constructor of ClassA
10:26:02.683 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanB'
In constructor of ClassB

As you can see from the output beanA is initialized first.

Using depends-on with multiple beans

If there is a dependency on multiple beans, supply a list of bean names as the value of the depends-on attribute (commas, whitespace, and semicolons are valid delimiters).

<bean id="beanA" class="com.knpcode.springbeans.ClassA" />  
<bean id="beanB" class="com.knpcode.springbeans.ClassB" />
<bean id="beanC" class="com.knpcode.springbeans.ClassC" depends-on="beanA,beanB">  
</bean>

Spring @DependsOn annotation example

If you are using Spring Java configuration or annotation to scan components then you can use @DependsOn annotation in Spring to explicitly force one or more beans to be initialized first. This annotation may be used directly on any class or indirectly annotated with Component or on methods annotated with Bean.

Following example shows the use of @DependsOn annotation where Spring Java configuration is used so @DependsOn annotation is used along with @Bean annotation.

public class ClassA {
  public ClassA(){
    System.out.println("In constructor of ClassA");
  }
  //static block
  static {
    System.out.println("in static block ClassA");
    System.out.println("Register DB Driver as a one time activity");
  }
}
public class ClassB {
  public ClassB(){
    System.out.println("In constructor of ClassB");
  }
}
public class ClassC {
  public ClassC(){
    System.out.println("In constructor of ClassC");
  }
}
Java configuration class
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import com.knpcode.springbeans.ClassA;
import com.knpcode.springbeans.ClassB;
import com.knpcode.springbeans.ClassC;

@Configuration
public class AppConfig {
  @Bean
  @DependsOn({"beanA","beanB"})
  public ClassC beanC() {
    return new ClassC();
  }
  @Bean
  public ClassB beanB() {
    return new ClassB();
  }
  @Bean
  public ClassA beanA() {
    return new ClassA();
  }
}

In the configuration there is a bean definition for ClassA, ClassB and ClassC. To enforce that beanA and beanB are initialized before beanC, @DependsOn annotation is used on bean definition of ClassC with beanA and beanB as values.

For running the application you can use the following class.

public class App {

  public static void main(String[] args) {
    AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    ClassC obj = context.getBean("beanC", ClassC.class);
    context.close();
  }
}
Output
10:52:01.160 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanA'
in static block ClassA
Register DB Driver as a one time activity
In constructor of ClassA
10:52:01.293 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanB'
In constructor of ClassB
10:52:01.297 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'beanC'
In constructor of ClassC

As you can see from the output beanA and beanB are initialized first.

That's all for the topic Spring depends-on Attribute and @DependsOn Annotation. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment