Spring BeanDefinition

0

In this article, we will discuss the basic flow involved in loading the bean definitions.A bean factory can be created from multiple locations. Each location pattern can result in more than one actual resource of bean definitions.We will only touch the outer flow and not the actual parsing of bean definitions.

Libraries

The examples written in this article loads bean definitions. If you want to download the source code and run the examples, you need below three jars and junit.jar:

  1. spring-beans-4.1.4.RELEASE.jar
  2. spring-core-4.1.4.RELEASE.jar
  3. commons-logging.jar

Creation of BeanFactory from multiple context files

A bean factory can be created from context files residing in more than one location path. In the below test, we pass in two location paths, the first location is of pattern context*.xml and other is the actual file name aliasContext.xml. The first location results in three context files context1.xml, context2.xml and context3.xml. The third context file, context3.xml, has import element which imports another context file testImport.xml. In the below example, I am creating a bean reader and then loading bean factory for multiple context files.

    public void testBasicBeanLoadingFromMultipleContexts() {
        System.clearProperty("spring.profiles.active");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(
                factory);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath*:context*.xml",
                "classpath*:aliasContext.xml");
    }

Context files with profile, nested beans, import and alias elements

The contents of the context files have been chosen so as to understand the main flow. It has bean, nested beans, import and alias elements. Each element will be discussed in detail in my coming posts.

context1.xml:

<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.1.xsd"
       profile="dev">
    <bean id="bean1" class="org.springframework.tests.sample.beans.TestBean"/>
    <bean id="bean2" class="org.springframework.tests.sample.beans.TestBean"/>
    <beans profile="dev">
        <bean id="devBean1" class="org.springframework.tests.sample.beans.TestBean"/>
    </beans>
    <beans profile="test">
        <bean id="testBean1" class="org.springframework.tests.sample.beans.TestBean"/>
    </beans>
</beans>

Other than the bean elements, it has two other nested beans element for different profiles.

context2.xml:

<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.1.xsd">
    <bean id="bean3" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

It just has one bean element.

context3.xml:

<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.1.xsd">
    <import resource="testImport.xml"/>
</beans>

It has an import element which imports resources from the location path in the resource attribute.

aliasContext.xml:

<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.1.xsd">
    <alias name="bean1" alias="bean1Alias"/>
</beans>

It has an alias element to register aliases.

testImport.xml:

<?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.1.xsd">
    <bean id="importedBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

This is imported from context3.xml. It just has one bean element.

Load beans without any profile set

In this example, we will not set the active profile, so it will skip loading beans meant for specific profiles.
factory.containsBeanDefinition(beanId) return us true if the bean definition is loaded. Note that if bean definition is loaded it doesn’t mean bean itself is loaded.
factory.isAlias(aliasId) returns true if there is a bean mapped for the alias passed in.
Assert statements confirm that the beans (beans from import and the nested beans) and alias are registered.
To know more about profiles, read my spring profiles article.

    public void testBasicBeanLoadingFromMultipleContexts() {
        System.clearProperty("spring.profiles.active");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(
                factory);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath*:context*.xml",
                "classpath*:aliasContext.xml");
        assertTrue(factory.containsBeanDefinition("bean1"));
        assertTrue(factory.containsBeanDefinition("bean2"));
        assertFalse(factory.containsBeanDefinition("testBean1"));
        assertFalse(factory.containsBeanDefinition("devBean1"));
        assertTrue(factory.containsBeanDefinition("bean3"));
        assertTrue(factory.containsBeanDefinition("importedBean"));
        assertTrue(factory.isAlias("bean1Alias"));
    }

Load beans for dev profile

Beans which are without any profile are loaded. Beans with dev profile are also loaded. But the beans meant for test profile are not loaded.

public void testBeansLoadedForDevProfile() {
        System.setProperty("spring.profiles.active", "dev");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(
                factory);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath*:context*.xml",
                "classpath*:aliasContext.xml");
        assertTrue(factory.containsBeanDefinition("bean1"));
        assertTrue(factory.containsBeanDefinition("bean2"));
        assertTrue(factory.containsBeanDefinition("devBean1"));
        assertFalse(factory.containsBeanDefinition("testBean1"));
        assertTrue(factory.containsBeanDefinition("bean3"));
        assertTrue(factory.containsBeanDefinition("importedBean"));
        assertTrue(factory.isAlias("bean1Alias"));
    }

Load beans for test profile

public void testBeansLoadedForTestProfile() {
        System.setProperty("spring.profiles.active", "test");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(
                factory);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath*:context*.xml",
                "classpath*:aliasContext.xml");
        assertTrue(factory.containsBeanDefinition("bean1"));
        assertTrue(factory.containsBeanDefinition("bean2"));
        assertFalse(factory.containsBeanDefinition("devBean1"));
        assertTrue(factory.containsBeanDefinition("testBean1"));
        assertTrue(factory.containsBeanDefinition("bean3"));
        assertTrue(factory.containsBeanDefinition("importedBean"));
        assertTrue(factory.isAlias("bean1Alias"));
    }

Flow involved in loading Bean Definitions

The location patterns are converted to actual resources. Each resource is loaded into a document which is parsed to register the beans. The profile is checked to make sure the beans belong to one of the active profiles. If not, the beans element will be ignored  First the beans default attributes are parsed and then each of the elements within the beans element are parsed. Each context file contains one or more bean element. Other than bean elements, we may also have one or more of the below elements. Once the bean element is parsed, a bean definition will be created and registered in the factory.

  1. import
  2. alias
  3. beans

Basic flow of loading bean definitions -1

Download source code

In this article, I showed you the basic flow involved while loading bean definitions. Our example had multiple context files where one of the context files was loaded using import element. The context files had some simple beans including an alias.

Download the source code springbeans.zip

Share.

Leave A Reply