Bean definition inheritance means that you have lot of bean definition in the bean configuration file and you have something that is common across lots of bean. There is a common setter value that has to be initialized across multiple beans and only then bean definition inheritance can be used.
You can have one parent bean that contains all of these common definitions inside it, and then you can inherit all the common bean definitions across the other bean. This parent bean, which has all the common definitions, can be a bean in itself. This parent bean can be made into abstract bean definitions, so there are no beans created for it, and all it does is for the purpose of templating a bean definition.
From a parent bean definition, a child bean definition inherits configuration data and can override or add values, as required. In an XML-based configuration file, a child bean definition is indicated using a parent attribute that specifies the parent bean as the value of this attribute. Refer to the following table for clarity:
Beans |
Description |
---|---|
|
|
|
|
ParentBean
and ChildBean
are explained as follows:
ParentBean
: This is a parent bean that is used as a template to create other beans. It would be referred to in the XML file with id="pBean"
.ChildBean
: This is a child bean that inherits from the parent bean defined earlier. The parent="pBean"
specifies that this bean is inheriting the properties of the ParentBean
bean.The child bean must accept the parent bean's property values. The child bean definition inherits constructor argument values and property values from the parent bean definition. The child bean definition overrides the initialization method setting and destroys method setting from the parent bean definition.
Spring bean definition inheritance is not related with the Java class inheritance. A parent bean is defined as a template and child beans can inherit the required configuration from this parent bean.
Now, the following example illustrates bean definition inheritance.
In the Employee.java
class, you'll find the following code:
package org.packt.Spring.chapter2.beaninheritance; public class Employee { private int employeeId; private String employeeName; private String country; public void setEmployeeId(int employeeId) { this.employeeId = employeeId; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } public void setCountry(String country) { this.country = country; } @Override public String toString() { return "Employee ID: " + employeeId + " Name: " + employeeName + " Country: " + country; } }
In the preceding code snippet, the Employee
class contains properties named employeeName
, employeeId
, country
, and their corresponding setter method. This class has also overridden the toString()
method.
The Spring bean configuration file, beans.xml
, where we defined the indianEmployee
bean as a parent bean with the country
property and its value. Next, an employeeBean
bean has been defined as the child bean of indianEmployee
using the parent="indianEmployee"
parent attribute. The child bean inherits country
properties from the parent bean and introduces two more properties, employeeId
and employeeName
.
In the beans.xml
file, you'll find the following code:
... <bean id="indianEmployee" class="org.packt.Spring.chapter2.beaninheritance.Employee"> <property name="country" value="India"></property> </bean> <bean id="employeeBean" parent="indianEmployee"> <property name="employeeId" value="1065"></property> <property name="employeeName" value="Ravi Kant Soni"></property> </bean> ...
In the PayrollSystem.java
class, you'll find the following code:
package org.packt.Spring.chapter2.beaninheritance; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class PayrollSystem { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml"); // using 'employeeBean' Employee employeeA = (Employee) context.getBean("employeeBean"); System.out.println(employeeA); // using 'indianEmployee' Employee employeeB = (Employee) context.getBean("indianEmployee"); System.out.println(employeeB); } }
When we run the PayrollSystem
class, the result will be as follows:
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1c4f0f8: startup date [Sun Jan 25 14:31:50 IST 2015]; root of context hierarchy Jan 25, 2015 2:31:51 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] Employee ID: 1065 Name: Ravi Kant Soni Country: India Employee ID: 0 Name: null Country: India
Here, the indianEmployee
bean is able to instantiate. In the indianEmployee
bean, we have only set the value for the country
property, so other fields get the null
value. In the employeeBean
, we have set only two properties, which are employeeId
and employeeName
, and the country
property is inherited from the indianEmployee
bean, so all the fields get their value for employeeBean
.
Inheritance with abstract helps in creating a bean definition as a template, which cannot be instantiated and serves as a parent definition for child definitions. While defining a bean definition as a template, you should specify only the abstract
attribute with the value true
, for example, abstract="true"
.
In the beans.xml
file, you'll find the following code:
... <bean id="indianEmployee" class="org.packt.Spring.chapter2.beaninheritance.Employee" abstract="true"> <property name="country" value="India"></property> </bean> <bean id="employeeBean" parent="indianEmployee"> <property name="employeeId" value="1065"></property> <property name="employeeName" value="Ravi Kant Soni"></property> </bean> ...
The parent bean indianEmployee
cannot be instantiated on its own because it is explicitly marked as abstract
. When a bean definition is abstract
, that bean definition is served as a pure template bean definition and used as a parent definition for child definitions. So, while running the PayrollSystem
class, the following code snippet will result in an error message on the console:
... // using 'indianEmployee' Employee employeeB = (Employee) context.getBean("indianEmployee"); System.out.println(employeeB); ...
Since the indianEmployee
bean is a pure template, if you try to instantiate it, you will encounter the following error message:
org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'indianEmployee': Bean definition is abstract