A Hybrid SessionFactoryBean

By Kenan Sevindik

The LocalSessionFactoryBean is a convenient way to create and initialize a Hibernate SessionFactory instance in applications. It allows us to configure other objects and properties, such as DataSource, and other Hibernate properties that the SessionFactory instance depends on during initialization inside Spring’s context mechanism. We can easily configure other parts of our application that are related to the SessionFactory instance in this manner. For example, we currently have an audit logging mechanism based on Hibernate’s entity interceptor, and this part of our application needs to be integrated into the Spring context.

There might be cases where the SessionFactory must be shared across multiple applications. In such cases, we can wire one up via JndiObjectFactoryBean, starting up the SessionFactory instance via a separate mechanism outside the applications and registering it in a JNDI context as a server-wide resource in a J2EE application server environment.

We find ourselves in a similar situation as mentioned above: we have many modules, each running as a separate web application in our system, and each one requiring a SessionFactory instance. SessionFactory instances are identical across all modules, i.e., each one loads the same Hibernate mapping files, connects to the same database, and employs the same properties. Hence, it would be sufficient for one of those modules to bring a SessionFactory instance up and make it available to all other modules. That way, we might achieve at least a performance improvement during our modules’ startup period.

We needed a way to start a SessionFactory instance up inside the Spring context and then register it as a server-wide resource in the JNDI context in the application server environment. Consequently, we merged the functionalities of both LocalSessionFactoryBean and JndiObjectFactoryBean classes to accomplish our task, and named it JndiEnabledLocalSessionFactoryBean.

It extends from LocalSessionFactoryBean and adds some additional properties to enable JNDI lookup, namely jndiName, jndiAccessor, and enableJndiLookup. If enableJndiLookup is true, it first attempts to load the SessionFactory instance from the specified JNDI location. If an available instance is found, it is provided to our application; otherwise, it initializes a SessionFactory instance and registers it to that JNDI location. This way, other modules will avoid initializing a new instance separately each time. If the enableJndiLookup property is false, it behaves as an ordinary LocalSessionFactoryBean instance, which might be preferable for a development environment.

Here is an excerpt from the source code and bean definition from the Spring context file:

public class JndiEnabledLocalSessionFactoryBean extends LocalSessionFactoryBean {

    private Object sessionFactoryObject;
    private String jndiName;
    private JndiAccessor jndiAccessor;
    private boolean enableJndiLookup;

    public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
        try {
            if(isEnableJndiLookup()) {
              sessionFactoryObject = getJndiAccessor().getJndiTemplate().lookup(getJndiName());
            } else {
                initializeSessionFactory();
            }
        } catch (NamingException e) {
            initializeSessionFactory();
            try {
                 getJndiAccessor().getJndiTemplate().bind(getJndiName(),super.getObject());
            } catch (NamingException e1) {
                logger.warn("Cannot bind SessionFactory to JNDI Context",e1);
            }
        }
    }

    private void initializeSessionFactory() throws HibernateException, IOException {
        super.afterPropertiesSet();
        sessionFactoryObject = super.getObject();
    }
    public void destroy() throws HibernateException {
        if(isEnableJndiLookup()) {
               try {
                   getJndiAccessor().getJndiTemplate().unbind(getJndiName());
               } catch (NamingException e) {
                   logger.warn("Cannot unbind SessionFactory from JNDI Context",e);
               }

        }
        super.destroy();
    }

    public Object getObject() {
        return sessionFactoryObject;
    }

    //getter and setter methods for properties defined above, jndiName, jndiAccessor, enableJndiLookup
}
<bean id="sessionFactory" class="tbs.verisozlugu.ambar.JndiEnabledLocalSessionFactoryBean">
      <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
      </property>
      <property name="dataSource">
            <ref local="dataSource" />
      </property>
      <property name="jndiName">
            <value>vsSessionFactory</value>
      </property>
      <property name="enableJndiLookup">
            <value>false</value>
      </property>
      <property name="jndiAccessor">
            <ref local="jndiAccessor"/>
      </property>
</bean>

<bean id="jndiAccessor" class="org.springframework.jndi.JndiAccessor">
      <property name="jndiEnvironment">
            <value>
                  java.naming.factory.initial=org.exolab.jms.jndi.InitialContextFactory
                  java.naming.provider.url=rmi://localhost:1099
            </value>
      </property>
</bean>
Share: X (Twitter) LinkedIn