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
You may also like-
No comments:
Post a Comment