Spring Bean Definition Inheritance
0 CommentsLast Updated on September 12, 2019 by jt
Using inheritance can be a valuable time saver for your Spring Framework configurations.
In Spring, a bean definition is the configuration information that we provide for beans. For example, bean definition can include property values and constructor arguments of the bean. Bean definition can also include container-specific information, such as init and destroy method settings, bean post processor, and so on.
We can provide Bean definition through XML configuration or Java Annotations.
An enterprise application typically contains a large number of beans and there are often configurations that are shared amongst beans.
In order to promote reusability and minimize development effort, Spring supports bean definition inheritance.
In this post, I will discuss how to implement bean definition inheritance.
Bean Definition Inheritance using XML Configuration
For the purpose of demonstration, let us take a simple Spring application. The application contains a single bean, Book
.
The code of the Book
bean is this.
package guru.springframework.xmlbasedbeandefinitioninheritance.domain; public class Book { private String bookName; private String bookAuthor; private float bookPrice; public Book() { } public Book(String bookName, String bookAuthor, float bookPrice) { this.bookName = bookName; this.bookAuthor = bookAuthor; this.bookPrice = bookPrice; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getBookAuthor() { return bookAuthor; } public void setBookAuthor(String bookAuthor) { this.bookAuthor = bookAuthor; } public float getBookPrice() { return bookPrice; } public void setBookPrice(float bookPrice) { this.bookPrice = bookPrice; } @Override public String toString() { return "Book{" + "bookName='" + bookName + '\'' + ", bookAuthor='" + bookAuthor + '\'' + ", bookPrice=" + bookPrice + '}'; } }
Next, we will write the Bean configuration to demonstrate bean definition inheritance.
The code of the beans.xml
file is this.
<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="BaseBook" class="guru.springframework.xmlbasedbeandefinitioninheritance.domain.Book" > <property name="bookName" value="Start Where You Are" /> </bean> <bean id="BookBean" parent="BaseBook"> <property name="bookAuthor" value="Meera Lee Patel" /> <property name="bookPrice" value="40.00" /> </bean> </beans
In the preceding code, the child bean BookBean
inherits from the BaseBook
bean using the parent attribute. Therefore, the parent definition will be inherited by the child. Note that the child bean is overridng the bookAuthor
and bookPrice
properties of the parent bean.
Now, let us write the main class BeanDefinitionInheritanceDemoApplication
.
package guru.springframework; import guru.springframework.xmlbasedbeandefinitioninheritance.domain.Book; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @SpringBootApplication public class BeanDefinitionInheritanceDemoApplication { public static void main(String[] args) { //XML based Bean Definition Test System.out.println("XML based Bean Definition Inheritance Test"); ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Book book = (Book) context.getBean("BookBean"); System.out.println("Book Details: " + book); }
The preceding class uses ClassPathXmlApplicationContext
to retrieve BookBean
, and display its fields.
Book Details: Book{bookName='Start Where You Are', bookAuthor='Meera Lee Patel', bookPrice=40.0}
As shown in the output, the Book
bean inherited the
Bean Definition Inheritance with Template
In the preceding example, BaseBook
is a concrete bean. At times, you might want to make BaseBook
as a pure template for bean definition inheritance. In such a scenario, you can declare BaseBean
as abstract, like this.
<bean id="BaseBook" class="guru.springframework.xmlbasedbeandefinitioninheritance.domain.Book" abstract="true"> <property name="bookName" value="Start Where You Are" /> </bean>
By declaring BaseBook
as abstract, you can ensure that it can’t be instantiated but only used as a template for bean definition inheritance.
Bean Definition Inheritance Using Annotations
Spring does not provide any annotation corresponding to the parent attribute of XML configuration. You can apply bean definition inheritance using plain old Java inheritance where a child bean extends a parent bean.
Let us start by creating a Book
class. The code of the Book
class is:
package guru.springframework.annotationbasedbeandefinitioninheritance.domain; public class Book { private String bookName; private float bookPrice; private String authorName; public Book() { } public Book(String bookName, float bookPrice, String authorName) { this.bookName = bookName; this.bookPrice = bookPrice; this.authorName = authorName; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public float getBookPrice() { return bookPrice; } public void setBookPrice(float bookPrice) { this.bookPrice = bookPrice; } public String getAuthorName() { return authorName; } public void setAuthorName(String authorName) { this.authorName = authorName; } @Override public String toString() { return "Book{" + "bookName='" + bookName + '\'' + ", bookPrice=" + bookPrice + ", authorName='" + authorName + '\'' + '}'; } }
Next, we will write the EPubBook
class which extends the Book
class.
package guru.springframework.annotationbasedbeandefinitioninheritance.domain; public class EPubBook extends Book { private String downloadUrl; public EPubBook() { } public EPubBook(String downloadUrl) { this.downloadUrl = downloadUrl; } public String getDownloadUrl() { return downloadUrl; } public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; } @Override public String toString() { return "EPubBook{" + "downloadUrl='" + downloadUrl + '\'' + '}'; } }
Now, let’s write the Java Configuration.
package guru.springframework.annotationbasedbeandefinitioninheritance.config; import guru.springframework.annotationbasedbeandefinitioninheritance.domain.Book; import guru.springframework.annotationbasedbeandefinitioninheritance.domain.EPubBook; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public EPubBook ePubBook() { EPubBook ePubBook = new EPubBook(); initBook(ePubBook); ePubBook.setDownloadUrl("http://example.epub.com/books/thinkandgrowrich.epub"); return ePubBook; } private void initBook(Book book) { book.setBookName("Think and Grow Rich"); book.setBookPrice(33.99f); book.setAuthorName("Napoleon Hill"); } }
Finally, the code of the main class is this.
package guru.springframework; import guru.springframework.annotationbasedbeandefinitioninheritance.config.AppConfig; import guru.springframework.annotationbasedbeandefinitioninheritance.do import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @SpringBootApplication public class BeanDefinitionInheritanceDemoApplication { public static void main(String[] args) { //Annotation based Bean Definition Test System.out.println("Annotation based Bean Definition Inheritance Test"); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class); ctx.refresh(); EPubBook ePubBook = ctx.getBean(EPubBook.class); System.out.println("Author Name: " + ePubBook.getAuthorName()); System.out.println("Book Name: " + ePubBook.getBookName()); System.out.println("Book Price: " + ePubBook.getBookPrice()); System.out.println("Download URL: " + ePubBook.getDownloadUrl()); ctx.registerShutdownHook(); } }
The output on running the main class is this.
Author Name: Napolean Hill Book Name: Think and Grow Rich Book Price: 33.99 Download URL: http://example.epub.com/books/thinkandgrowrich.epub
As shown in the output, EPubBook
inherited the bookName
, bookPrice
, and authorName
properties of Book
.
Summary
In Enterprise Applications, bean definition inheritance, when designed correctly, can eliminate lots of duplicate code. Also, any changes to configuration settings can be done in the base bean definition instead of updating in all the scattered definitions.
Few key things to remember. A child bean definition will inherit constructor argument values, property values, and method overrides from the parent. The child bean definition also can add new values. If the child bean contains init-method, destroy-method and/or static factory method settings, they override the corresponding parent settings.
The Settings that will always be taken from the child definition are depends on, autowire mode, dependency check, singleton, scope, lazy init.
The source code for this post can be found here on GitHub.