Search code examples
javaspringhibernateejb

Spring EJB Integration


In my application we have the following architecture:

  • Web Layer: JSF+Rich Faces
  • Service Layer: EJB
  • DAO Layer: EJB Classes [consist of JDBC Queries]

We want to use Hibernate as ORM framework instead of JDBC in DAO layer. I want to use Spring ORM feature for integrating Hibernate in DAO layer. Now, challenges that we are facing:

DAO layer classes are stateless EJB classes. So,to use Spring DI inside EJB classes, I have to go for an interceptor as follows:

@Stateless(mappedName = "myAppDao")
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyAppDaoImpl implements MyAppDaoRemote {

@Autowired
private SessionFactory sessionFactory;

@Override
public void getSession() {
     if(sessionFactory!=null){
        Session session = null;
        try{
            session = sessionFactory.getCurrentSession();
        }catch (Exception e) {
            session = sessionFactory.openSession();
            System.out.println("Exception:"+e.getMessage()); 
        }
}

With sessionFactory.getCurrentSession() I am getting this exception:

Exception:Could not obtain transaction-synchronized Session for current thread.

The reason behind this I am not able to use Spring transaction at Service layer since I have EJB classes in my service layer.

Moreover I don't want to use sessionFactory.openSession() as in that case I would have to manually close the session.

These are my Spring configuration files:

1) beanRefContext.xml -> Used by Interceptors

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

     <bean id="businessBeanFctory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
          <constructor-arg value="classpath*:daoConfig.xml" />
     </bean>
 </beans>

2) daoConfig.xml -> Hibernate Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:jee="http://www.springframework.org/schema/jee"
   xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/jee    http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
                    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/tx 
                    http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">

  <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="packagesToScan" value="com.myapp.model"/>
      <property name="hibernateProperties">
         <props>
            <prop  key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
          </props>
        </property>
    </bean>

   <jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyAppDS" expected-type="javax.sql.DataSource"/>

   <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>    
   <tx:annotation-driven transaction-manager="transactionManager" />

   </beans>

I know that there is no point in using EJB along with Spring since they are alternate to each other.But due to some restriction at project level I can't remove EJB for the time being.

So, is there any solution by which we can get the Hibernate current session inside an EJB class through Spring?


Solution

  • If you're using JBossAS/WildFly then you just need:

    @Stateless(mappedName = "myAppDao")
    public class MyAppDaoImpl implements MyAppDaoRemote {
    
        @PersistenceContext
        private Session session;
    
        public void someDaoMethod(YourEntity e) {
            // use session directly
            // Transactions are automatically managed by the EJB container
            // because that's one of EJB's raison d'être
        }
    
    }
    

    Ensure that your (traditional) Hibernate configuration specifies JTA transactions.

    See the WildFly JPA Reference Guide for more information.

    If you're not using one of these JavaEE implementations then you can still use the Spring configuration that you have, but remember to include:

     <property name="jtaTransactionManager" value="transactionManager"/>
    

    in your sessionFactory bean.

    Additionally, if you're using WebLogic or WebSphere you may need to specify platform dependent JTA transaction managers for these servers, such as WebLogicJtaTransactionManager or org.springframework.transaction.jta.WebSphereUowTransactionManager.