Search This Blog

Monday 16 September 2013

BeanFactory and Inheritance

Inheritance of Beans is a feature available in Spring Bean Factories. I decided to try the same using Spring's BeanFactory.
  1. The first step was to create a parent BeanFactory:
    final DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
    final XmlBeanDefinitionReader parentReader = new XmlBeanDefinitionReader(
    parentBeanFactory);
    parentReader.loadBeanDefinitions(new ClassPathResource("parent.xml"));
    final Simple rootBean = (Simple) parentBeanFactory.getBean("rootBean");
    
    where SimpleBean is a simple class:
    public class Simple {
    
       public String value;
       //setter getters
    }
    
    As XmlBeanFactory has been deprecated I decided to use the DefaultListableBeanFactory class.
  2. The parent.xml file is a simple beans file:
    <?xml version="1.0" encoding="UTF-8"?>
    <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-3.2.xsd">
       <bean id="rootBean" class="java.lang.String">
          <constructor-arg type="java.lang.String" value="Root" />
       </bean>
    </beans>
    
    It is present on the classpath. Running the above code would display the value for the bean.
  3. The next step was to create the child bean factory.
    DefaultListableBeanFactory childBeanFactory = new DefaultListableBeanFactory(parentBeanFactory);
    Simple childRootBean = (Simple) childBeanFactory.getBean("rootBean");
    System.out.println(rootBean + " " + childRootBean);
    System.out.println("Are the beans equal " + rootBean.equals(childRootBean));
    
    As seen here the DefaultListableBeanFactory takes the parent bean factory as a constructor parameter.
If I run the code the logs will indicate that the child was able to successfully access the "rootBean" which was inherited from the parent BeanFactory.
DEBUG DefaultBeanDefinitionDocumentReader:106 - Loading bean definitions
DEBUG DefaultListableBeanFactory:215 - Creating shared instance of singleton bean 'rootBean'
DEBUG DefaultListableBeanFactory:432 - Creating instance of bean 'rootBean'
DEBUG DefaultListableBeanFactory:506 - Eagerly caching bean 'rootBean' to allow for resolving potential circular references
DEBUG DefaultListableBeanFactory:460 - Finished creating instance of bean 'rootBean'
DEBUG DefaultListableBeanFactory:246 - Returning cached instance of singleton bean 'rootBean'
com.Simple@c2b2f6 com.Simple@c2b2f6
Are the beans equal true
What if the child factory and parent factory both define beans with the same name ? 
To test this I added a new XML "child.xml" to use with the child BeanFactory.
<?xml version="1.0" encoding="UTF-8"?>
<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-3.2.xsd">
   <bean id="rootBean" class="com.Simple">
      <constructor-arg value="Child" />
   </bean>
</beans>
The test code was changed as below:
public static void main(final String[] args) {

      final DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
      final XmlBeanDefinitionReader parentReader = new XmlBeanDefinitionReader(
            parentBeanFactory);
      parentReader.loadBeanDefinitions(new ClassPathResource("parent.xml"));
      final Simple rootBean = (Simple) parentBeanFactory.getBean("rootBean");

      DefaultListableBeanFactory childBeanFactory = new DefaultListableBeanFactory(parentBeanFactory);
      XmlBeanDefinitionReader childReader = new XmlBeanDefinitionReader(childBeanFactory);
      childReader.loadBeanDefinitions(new ClassPathResource("child.xml"));
      Simple childRootBean = (Simple) childBeanFactory.getBean("rootBean");
      System.out.println(rootBean + " " + childRootBean);
      System.out.println("Are the beans equal " + rootBean.equals(childRootBean));
   }
On running the code.... it runs.
com.Simple@6fa9fc com.Simple@100ebec
Are the beans equal false
How it works is that the child BeanFactory checks within its context if the bean is present. If not, then it turns to the parent BeanFactory. Hence the concern of conflicting names does not arise. The child definitions effectively override the Parent definitions. As we also saw the beans are inherited by names. This has nothing to do with the class hierarchy. Even this would work fine in child.xml:
<bean id="rootBean" class="java.lang.String">
      <constructor-arg value="Child" />
   </bean>
The java code:
String childRootBean = (String) childBeanFactory.getBean("rootBean");
System.out.println(rootBean + " " + childRootBean);
The output will display the two beans :
com.Simple@1815bfb Child
As seen, there are two beans with name "rootBean" and both fall from a completely different hierarchy.

1 comment: