Spring EJB 集成
Spring EJB Integration
在我的应用程序中,我们有以下架构:
- Web 层:JSF+Rich Faces
- 服务层:EJB
- DAO 层:EJB 类 [由 JDBC 个查询组成]
我们想在 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 事务管理器,例如 WebLogicJtaTransactionManager
或 org.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.
在我的应用程序中,我们有以下架构:
- Web 层:JSF+Rich Faces
- 服务层:EJB
- DAO 层:EJB 类 [由 JDBC 个查询组成]
我们想在 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 事务管理器,例如 WebLogicJtaTransactionManager
或 org.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.