Friday, 27 January 2017

Using depends-on attribute in Spring

If one bean is a dependency of 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 depends-on attribute. The depends-on attribute can explicitly force one or more beans to be initialized before the bean using this element is initialized.

As example -

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

 
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;
 }
}

Another class, ClassB with a constructor, but it doesn’t refer to class A in anyway.

 
public class ClassB {
 
 public ClassB(){
  System.out.println("Initializing ClassB");
 }
}

Now you want to make sure that the static block should have executed before the initialization of ClassB bean.

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 will yield -

in static block
Values 5 25
Initializing ClassA
Initializing ClassB

Now you can see that the ClassA is initialized first.

Dependency on multiple beans

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" />

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 Using depends-on attribute Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Dependency Injection using factory-method in Spring
  2. Wiring collections in Spring
  3. Run time injection using Spring Expression Language(SpEL)
  4. Bean definition inheritance in Spring
  5. How to inject prototype scoped bean in singleton bean

You may also like -

>>>Go to Spring tutorial page

No comments:

Post a Comment