Spring EJB 集成

Spring EJB Integration

在我的应用程序中,我们有以下架构:

我们想在 DAO 层使用 Hibernate 作为 ORM 框架而不是 JDBC。我想使用 Spring ORM 功能将 Hibernate 集成到 DAO 层中。现在,我们面临的挑战:

DAO 层 classes 是无状态 EJB classes。因此,要在 EJB classes 中使用 Spring DI,我必须按如下方式使用拦截器:

@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()); 
        }
}

使用 sessionFactory.getCurrentSession() 我得到这个异常:

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

这背后的原因是我无法在服务层使用 Spring 事务,因为我的服务层中有 EJB classes。

此外,我不想使用 sessionFactory.openSession(),因为那样的话我将不得不手动关闭会话。

这些是我的 Spring 配置文件:

1) beanRefContext.xml -> 被拦截器使用

<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 -> 休眠配置

<?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>

我知道将 EJB 与 Spring 一起使用是没有意义的,因为它们是相互替代的 other.But 由于项目级别的某些限制,我暂时无法删除 EJB .

那么,是否有任何解决方案可以通过 Spring 在 EJB class 中获取 Hibernate 当前会话?

如果您使用 JBossAS/WildFly,那么您只需要:

@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
    }

}

确保您的(传统)Hibernate 配置指定 JTA 事务。

有关详细信息,请参阅 WildFly JPA Reference Guide

如果您没有使用这些 JavaEE 实现之一,那么您仍然可以使用现有的 Spring 配置,但请记住包括:

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

在你的 sessionFactory bean 中。

此外,如果您使用的是 WebLogic 或 WebSphere,您可能需要为这些服务器指定依赖于平台的 JTA 事务管理器,例如 WebLogicJtaTransactionManagerorg.springframework.transaction.jta.WebSphereUowTransactionManager

我已经按照以下方式修改了我的daoConfig.xml

<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.oms.model"/>
    <property name="jtaTransactionManager" ref="transactionManager"/>
    <property name="hibernateProperties">
       <props>
          <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
          <prop key="hibernate.show_sql">true</prop>
       </props>
    </property>
</bean>

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

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>   


</beans>

我已经添加了<property name="jtaTransactionManager" ref="transactionManager"/>sessionFactory bean definition.After 下面我可以使用

session = sessionFactory.getCurrentSession();在我的dao层class.