Spring Bean Definition Inheritance

Spring Bean Definition Inheritance

0 Comments

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.

About SFG Contributor

Staff writer account for Spring Framework Guru

    You May Also Like

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.