For a large-scale application, there can be hundreds of bean declared in the Spring IoC container and managing dependency between them will be already complicated. Especially through Setter Injection, we cannot make sure that values for all the properties has been injected. Spring dependency checking feature will come into rescue in this situation which helps us to check if all/ certain property is injected or not. Spring dependency check can be turned on just by adding “dependency-check” attribute of the <bean> tag.
Spring Dependency Checking modes
- none – No dependency checking will be performed, any property can be left as blank.
- simple – If any properties of primitive type (int, long, …) and collection types (map, list..) have not been set, UnsatisfiedDependencyException will be thrown.
- objects – If any properties of object type (other than the simple types) have not been set, UnsatisfiedDependencyException will be thrown.
- all – If any properties of any type have not been set, an UnsatisfiedDependencyException will be thrown.
Note : The default mode is none. Spring dependency checking feature can only check if the properties has been set or not, but it cannot check if value set is null or not.
Simple Type Dependency check example
Folder Structure:
- Create a new Java Project “SpringCoreTutorial” and create a package for our src files “com.javainterviewpoint“
- Add the required libraries to the build path. Java Build Path ->Libraries ->Add External JARs and add the below jars.
commons-logging-1.2.jar
spring-beans-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar - Create the Java classes Employee.java, PermanentEmployee.java and EmployeeLogic.java under com.javainterviewpoint folder.
- Place our configuration file SpringConfig.xml in the src directory
Employee.java
Lets take our Employee bean, if we haven’t set the value for the “name” property it will be set to null by default. Those kind of situation will be hard to debug. Fortunately Spring dependency checking will help us validation those scenarios. In order to make Spring IoC Container to check for the Simple type properties we need to set the dependency-check attribute of <bean> to simple.
package com.javainterviewpoint; public class Employee { public String name; public int age; public Employee() { super(); } public Employee(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + "]"; } }
Declaring Bean Configuration File (SpringConfig.xml)
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="emp" class="com.javainterviewpoint.Employee" dependency-check="simple"> <property name="age" value="100"></property> </bean> </beans>
- We have declared a bean for our Employee class and have set the dependency-check to simple.
- Using the Spring Setter Injection we are injection value only for the age property and not the name property.
EmployeeLogic.java
package com.javainterviewpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class EmployeeLogic { public static void main(String args[]) { //Read the Configuration file using ApplicationContext ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringConfig.xml"); //Get the Employee class instance Employee employee = (Employee)applicationContext.getBean("emp"); //Print the PermanentEmployee details System.out.println("**** Employee Details ****"); System.out.println("Employee Name : "+employee.getName()); System.out.println("Employee Age : "+employee.getAge()); } }
- In our EmployeeLogic class we have read the Configuration file(SpringConfig.xml) and get all the bean definition through ApplicationContext
- Get the Employee Class instance by calling the getBean() method over the context created.
Output :
Upon running our EmployeeLogic class we will be getting the exception like “unsatisfieddependencyexception error creating bean with name”, as we have not set the value for the “name” property and have set the dependency-check to simple.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'emp' defined in class path resource [SpringConfig.xml]:
Unsatisfied dependency expressed through bean property 'name': Set this property value or
disable dependency checking for this bean.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
checkDependencies(AbstractAutowireCapableBeanFactory.java:1416)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
populateBean(AbstractAutowireCapableBeanFactory.java:1222)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
Objects Type Dependency check example
If suppose our Employee class is dependent on other bean like PermanentEmployee class, then we will be using Spring Bean referencing to reference. But when PermanentEmployee is not set then we will be getting NulPointerException. In order to avoid that we will be enabling Spring dependency checking for bean properties of object types, Just change the dependency-check attribute to “objects”.
Employee.java
package com.javainterviewpoint; public class Employee { private PermanentEmployee pe; public Employee() { super(); } public Employee(PermanentEmployee pe) { super(); this.pe = pe; } public PermanentEmployee getPe() { return pe; } public void setPe(PermanentEmployee pe) { this.pe = pe; } }
SpringConfig.xml
In our configuration file we are not injecting reference to the property “pe”
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="emp" class="com.javainterviewpoint.Employee" dependency-check="objects"> </bean> </beans>
EmployeeLogic.java
package com.javainterviewpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class EmployeeLogic { public static void main(String args[]) { //Read the Configuration file using ApplicationContext ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringConfig.xml"); //Get the Employee class instance Employee employee = (Employee)applicationContext.getBean("emp"); //Print the PermanentEmployee details System.out.println(employee.getPe().getSalary()); } }
Output :
Without injecting the reference when we run our EmployeeLogic class we will be getting “UnsatisfiedDependencyException” like below
All Types Dependency check example
If you want to check the dependency of all bean properties whatever the type is, you can change the dependency-check attribute to “all”.
Our configuration file will be like below
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="emp" class="com.javainterviewpoint.Employee" dependency-check="all"> </bean> </beans>
Spring @Required annotation
Spring dependency checking feature can check only for all properties is set or not, you cannot validate only for certain properties only.But In most of the cases, we will be in need to check if particular properties have been set, but not all properties. In those times Spring @Required annotation comes into resuce. RequiredAnnotationBeanPostProcessor is a Spring bean post processor which checks for if the property with @Required annotation is set or not. To enable this Spring bean post processor we need register it in the Spring IoC Container.
If you are using Spring 2.5 we can register RequiredAnnotationBeanPostProcessor like below
<bean class=”org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor” />
If you are using Spring 3 and above we can simply include “<context:annotation-config>”
Spring @Required annotation example
Lets now see how @Required annotation how it helps in validating dependency. Lets take the above example code itself
Employee.java
we have put on @Required annotation on setters of both name and age properties. So when the value is not set for the name and age property IoC container will throw BeanInitializationException.
package com.javainterviewpoint; import org.springframework.beans.factory.annotation.Required; public class Employee { public String name; public int age; public Employee() { super(); } public Employee(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } @Required public void setName(String name) { this.name = name; } public int getAge() { return age; } @Required public void setAge(int age) { this.age = age; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + "]"; } }
Declaring Bean Configuration File (SpringConfig.xml)
<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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config></context:annotation-config> <bean id="emp" class="com.javainterviewpoint.Employee"> <property name="age" value="100"></property> </bean> </beans>
- We have declared a bean for our Employee class.
- Using the Spring Setter Injection we are injection value only for the age property and not the name property. Now Spring will throw BeanInitializationException as we have not injected value for the name property
Output :
Upon running our EmployeeLogic class, we will be getting the below exception as we will have not set value for name.
Note :
cvc-complex-type.3.2.2: attribute ‘dependency-check’ is not allowed to appear in element ‘bean’
(or)
attribute ‘dependency-check’ is not allowed to appear in element ‘bean’
Sometimes we will be getting above message while using Spring dependency check, this is because the dependency-check attribute has been deprecated since Spring 3.0. Either we can use @Required annotation or change the schema xsd version from 3.0 to 2.5
Leave a Reply