First aspect of layering using spring BeanFactoryLocator

0

A complex J2EE app is composed of multiple layers.

For example

  1. Presentation
  2. Application or Service Layer
  3. Domain or Business layer
  4. Data Access or Persistence Layer

Each layer may have its own ApplicationContext definition.

We will begin exploring layering using an example of SingletonBeanFactoryLocator which will be used to load these contexts.

Layers in an enterprise application

Enterprise Application Architecture

Enterprise Application Architecture

Layers as Enum

The layers in an enterprise application:

Let’s have the layers as enum.

Layers:

package com.javarticles;
public enum Layers {
    PRESENTATION,
    APPLICATION,
    DOMAIN,
    PERSISTENCE
}

Context file per Layer

Define the factory bean for each layer in beanRefFactory.xml. For example, below we have created one for the Domain layer. It is composed of context files DomainContext1.xml and DomainContext2.xml.

beanRefFactory.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.xsd">
    <bean id="DOMAIN" class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg>
            <list>
                <value>DomainContext1.xml</value>
                <value>DomainContext2.xml</value>                
            </list>
        </constructor-arg>
    </bean> 
</beans>

DomainContext1.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.xsd">
    <bean id="domain1" class="com.javarticles.business.DomainObject1">
    	<constructor-arg index="0" value="D1"/>
    </bean>	
</beans>

DomainContext2.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.xsd">
    <bean id="domain2" class="com.javarticles.business.DomainObject2">
    	<constructor-arg index="0" value="D2"/>
    </bean>	
</beans>

Domain Layer

In our domain layer , we have simple beans DomainObject1 and DomainObject2.

DomainObject1:

package com.javarticles.business;

public class DomainObject1 {
    private String s;
    public DomainObject1(String s) {
        this.s = s;
    }
    public String getS() {
        return s;
    }    
}

DomainObject2:

package com.javarticles.business;

public class DomainObject2 {
    private String s;
    public DomainObject2(String s) {
        this.s = s;
    }
    public String getS() {
        return s;
    }    
}

Create BeanFactoryLocator

We will call SingletonBeanFactoryLocator.getInstance() to create the topmost bean factory which will contain the layer specific bean factories. We can either pass the location path of the resources to it or just leave it empty in which case it will load beanRefFactory.xml file from the classpath.

bfl.useBeanFactory("DOMAIN") will return us the Bean Factory for the domain layer. We will cache the bean factory as we load so on next time we can simply return it from cache. Note that SingletonBeanFactoryLocator itself caches the topmost factory so further caching will only help us avoid calling topmostbeanFactory.getBean("layer key").

LayerContext:

package com.javarticles.business;

import java.util.EnumMap;
import java.util.Map;

import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;

import com.javarticles.Layers;

public class LayerContext {
    protected static ListableBeanFactory createBeanFactory(Layers factoryKey) {
        if (BEAN_FACTORY_BY_LAYER.containsKey(factoryKey)) {
            return BEAN_FACTORY_BY_LAYER.get(factoryKey);
        }
        BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();        
        BeanFactoryReference bfReference = bfl.useBeanFactory(factoryKey.name());
        ListableBeanFactory topmostBeanFactory = (ListableBeanFactory) bfReference.getFactory();
        BEAN_FACTORY_BY_LAYER.put(factoryKey, topmostBeanFactory);
        return topmostBeanFactory;
    }

    private static final Map<Layers, ListableBeanFactory> BEAN_FACTORY_BY_LAYER =
            new EnumMap<Layers, ListableBeanFactory>(Layers.class);    
}

Now let’s look into the DomainContext which will subclass LayerContext to return us the Domain specific factory.

DomainContext:

package com.javarticles.business;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;

import com.javarticles.Layers;

public class DomainContext extends LayerContext {

    public static boolean containsBean(String beanName) {
        return getBeanFactory().containsBean(beanName);
    }
    
    public static Object getBean(String beanName) {
        BeanFactory beanFactory = getBeanFactory();

        Object retBean = null;
        try {           
            retBean = beanFactory.getBean(beanName);
        } catch (BeansException e) {
            System.out.println("Exception while getting the bean " + beanName + e);
            throw e;
        }
        return retBean;
    }

    private static synchronized BeanFactory getBeanFactory() {
        if (beanFactory == null) {
            beanFactory = createBeanFactory(Layers.DOMAIN);
        }
        return beanFactory;
    }

    private static ListableBeanFactory beanFactory;
}

Retrieve the domain specific beans

Let’s now retrieve the domain specific beans DomainObject1 and DomainObject2.

SpringBeanFactoryLocatorExample:

package com.javarticles.business;

public class SpringBeanFactoryLocatorExample {
    public static void main(String[] args) {
        DomainObject1 d1 = (DomainObject1) DomainContext.getBean("domain1");
        System.out.println(d1.getS());
        
        DomainObject2 d2 = (DomainObject2) DomainContext.getBean("domain2");
        System.out.println(d2.getS());        
    }
}

Output:

D1
D2

Download the source code

This was an example about BeanFactoryLocator. We looked into the the first aspect of layering to get the layer specific bean factory. You can download the source code here: springLayeringExample.zip

Share.

Comments are closed.