March 15, 2022

Spring Bean Definition Inheritance

Just like the OOPS concept of inheritance is used in object oriented language where child class can inherit attributes and methods of a parent class same way in Spring framework child bean can inherit configuration data from a parent definition. In this post we’ll see how bean definition inheritance works in Spring.

Bean definition inheritance in Spring

A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information, such as the initialization method, a static factory method name, and so on. A child bean definition can inherit that configuration information from a parent bean rather than defining everything again. The child definition can override some values or add others as needed.

How does bean definition inheritance work

Parent bean definition that is inherited in the child bean definition is specified using parent attribute of the <bean> element. For example in the following configuration parent bean definition is inherited by empBean using the parent attribute and it inherits the property company from parent bean definition and adds name property of its own.

<bean id="baseEmpBean" class="com.knpcode.Employee">
  <property name="company" value="XYZ"/>
</bean> 
    
<bean id="empBean" parent="baseEmpBean">
  <property name="name" value="Jack" />
</bean>
In the configuration you can see that the child bean definition doesn’t specify a bean class.

A child bean definition doesn't need to specify a bean class it can use the bean class from the parent definition. Though child bean definition can also override bean class, if it does then the child bean class must be compatible with the parent (that is, it must accept the parent’s property values). For example-

<bean id="parentBean" class="com.knpcode.TestBean">
  <property name="name" value="parent"/>
  <property name="mode" value="inherit"/>
</bean>

<bean id="childBean" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" >
  <property name="name" value="override"/>
  <!--  mode property value will be inherited from parent -->
</bean>

Spring Bean definition inheritance Example

In the example there is a bean class Employee with properties empId, empName, company, dept. In the parent definition value for company property is assigned which is inherited by the child bean definition.

public class Employee {
  int empId;
  String empName;
  String company;
  String dept;
  public int getEmpId() {
    return empId;
  }
  public void setEmpId(int empId) {
    this.empId = empId;
  }
  public String getEmpName() {
    return empName;
  }
  public void setEmpName(String empName) {
    this.empName = empName;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
  public String getCompany() {
    return company;
  }
  public void setCompany(String company) {
    this.company = company;
  }

  @Override
  public String toString() {
    return "Id= " + getEmpId() + " Name= " + 
             getEmpName() + " Dept= "+ getDept()
             + " Company= " + getCompany();
  }
}
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
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
    
  <bean id="baseEmpBean" class="com.knpcode.springproject.model.Employee">
    <property name="company" value="XYZ"/>
  </bean> 
  <bean id="empBean" parent="baseEmpBean">
    <property name="empId" value="1" />
    <property name="empName" value="Jack" />
    <property name="dept" value="HR" />
  </bean>
</beans>

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

public class App {
  public static void main( String[] args ){
    // create context using configuration
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    Employee emp =  context.getBean("empBean", Employee.class);
    System.out.println(emp);
    context.close();
  }
}
Output
20:09:24.009 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'baseEmpBean'
20:09:24.140 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'empBean'
Id= 1 Name= Jack Dept= HR Company= XYZ

Abstract attribute in Spring Bean definition inheritance

If you want to restrict instantiation of parent bean then you can mark it as abstract="true" to do that.

Abstract attribute in Spring bean definition
<?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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
  <!-- acts as a template -->
  <bean id="baseEmpBean" abstract="true" class="com.knpcode.springproject.model.Employee">
    <property name="company" value="XYZ"/>
  </bean> 
  <bean id="empBean" parent="baseEmpBean" >
    <property name="empId" value="1" />
    <property name="empName" value="Jack" />
    <property name="dept" value="HR" />
  </bean>
</beans>

With parent marked as abstract trying to access parent bean results in an error.

Exception in thread "main" org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'baseEmpBean': Bean definition is abstract
	at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:295)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111)
	at com.knpcode.springproject.App.main(App.java:14)

Parent bean as Template in Spring bean inheritance

By marking parent bean definition as abstract=”true” and not specifying a class too you can use parent only as a pure template bean definition that serves as a parent definition for child definitions.

Note that if the parent definition does not specify a class, explicitly marking the parent bean definition as abstract is required.

Template bean definition example
<?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
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
  <!-- acts as a template -->
  <bean id="baseEmpBean" abstract="true">
    <property name="company" value="XYZ"/>
  </bean> 
  <bean id="empBean" parent="baseEmpBean" class="com.knpcode.springproject.model.Employee">
    <property name="empId" value="1" />
    <property name="empName" value="Jack" />
    <property name="dept" value="HR" />
  </bean>
</beans>

That's all for the topic Spring Bean Definition Inheritance. 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