Friday, January 14, 2022

Spring depends-on Attribute and @DependsOn With Examples

This post talks about the depends-on attribute and its counterpart @DependsOn Annotation in Spring framework which helps when there is no explicit dependency on a bean.


Bean With no explicit dependency

If one bean has a dependency on another, that usually means that one bean is set as a property of another. In Spring framework, typically you accomplish this with the <ref/> element in XML-based configuration metadata.

Quite infrequently you may have a situation where one bean does not explicitly depend on another bean meaning it is not referred in another class as a property or a constructor argument. But one of the bean still depends on another bean and requires another bean to be initialized before its own initialization.

As example, a static initializer in a class needs to be triggered, such as database driver registration.
In that case you can use Spring depends-on attribute. The depends-on attribute (if you are using XML based configuration) or @DependsOn Annotation (if you are using annotations) can explicitly force one or more beans to be initialized before the bean using this element is initialized.

Spring depends-on attribute example

Suppose there is a class ClassA with it’s own fields, methods and a static block.

There is another class, ClassB with a constructor, but it doesn’t refer to ClassA in anyway. Now you want to make sure that the static block should have executed before the initialization of ClassB bean, which means ClassA should be initialized before ClassB.

 
public class ClassA {
 
 public ClassA(){
  System.out.println("Initializing ClassA");
 }
 // static blank final variable
 static final int i;
 static int b;
 //static block
 static {
  System.out.println("in static block");
  i = 5;
  b = i * 5;
  System.out.println("Values " + i + " " +  b);
 }
 public static int getB() {
  return b;
 }
 public static void setB(int b) {
  ClassA.b = b;
 }
 public static int getI() {
  return i;
 }
}
 
public class ClassB {
 public ClassB(){
  System.out.println("Initializing ClassB");
 }
}

If you define the beans in your XML configuration with out using depends-on attribute there is no guarantee that ClassA will be initialized first.

 
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <bean id="classB" class="org.netjs.prog.ClassB">   
    </bean>
    
    <bean id="classA" class="org.netjs.prog.ClassA">
    </bean>
</beans>

You can run it using this test class-

 
import org.netjs.prog.ClassB;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
   ("appcontext.xml");
  ClassB cbObj = (ClassB)context.getBean("classB");
  //cbObj.displayValue();
  context.close();
 }

}

Output

 
Initializing ClassB
in static block
Values 5 25
Initializing ClassA

Here you can see ClassB object is initialized first and then ClassA object is initialized and its static block is executed.
But that is not what you want so you can use depends-on attribute to tell the spring framework that ClassA object should be ready before initializing ClassB object.

In that case your XML configuration would change -

 
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <bean id="classB" class="org.netjs.prog.ClassB" depends-on="classA">  
    </bean>
    
    <bean id="classA" class="org.netjs.prog.ClassA">  
    </bean>
</beans>

Now running it using the test class yields-

 
in static block
Values 5 25
Initializing ClassA
Initializing ClassB

Now you can see that the ClassA is initialized first.

Dependency on multiple beans using depends-on attribute

To express a dependency on multiple beans, supply a list of bean names as the value of the depends-on attribute, with commas, whitespace and semicolons, used as valid delimiters:

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
      <property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

Spring @DependsOn annotation example

If you are using annotations then you can use @DependsOn annotation in Spring to explicitly force one or more beans to be initialized first.

If we take the same classes ClassA and ClassB as used above with the requirement that ClassA should be initialized before ClassB then using Java configuration bean definition will be as given below.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import com.netjstech.springcoreproj.beans.ClassA;
import com.netjstech.springcoreproj.beans.ClassB;

@Configuration
public class AppConfig {

	@Bean
	@DependsOn("beanA")
	public ClassB beanB() {
		return new ClassB();
	}
	@Bean
	public ClassA beanA() {
		return new ClassA();
	}
}

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);
    ClassB obj = context.getBean("beanB", ClassB.class);
    context.close();
  }
}

Output

in static block
Values 5 25
Initializing ClassA
Initializing ClassB

As you can see ClassA is initialized first.

Dependency on multiple beans using @DependsOn annotation

You can also specify more than one bean with @DependsOn annotation.

For example, there are three classes ClassA, ClassB and ClassC where ClassC needs ClassA and ClassB to be initialized before ClassC is initialized, then the configuration would be as given below.

@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();
  }
}

Controlling shutdown order

Dependent beans that define a depends-on relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. If you consider the above example, since ClassB bean is dependent on ClassA bean so ClassB bean will be destroyed first. But note that the destroy time dependency is specified in the case of singleton beans only.

That's all for this topic Spring depends-on Attribute and @DependsOn With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Dependency Injection Using factory-method in Spring
  2. Wiring Collections in Spring
  3. Spring Expression Language (SpEL) With Examples
  4. Bean Definition Inheritance in Spring
  5. How to Inject Prototype Scoped Bean into a Singleton Bean in Spring

You may also like-

  1. Spring JdbcTemplate Insert, Update And Delete Example
  2. How to Read Properties File in Spring Framework
  3. Difference Between HashMap and ConcurrentHashMap in Java
  4. Fail-Fast Vs Fail-Safe Iterator in Java
  5. Difference Between CountDownLatch And CyclicBarrier in Java
  6. CopyOnWriteArrayList in Java With Examples
  7. Java Multithreading Interview Questions And Answers
  8. Java Exception Handling And Method Overriding

No comments:

Post a Comment