Hibernate JPA 拦截器没有得到调用
Hibernate JPA interceptor doesn't get call
设置我有一个旧项目坚持jdk 1.5,因此spring和hibernate版本也是支持此版本java的最大可能。 Hibernate 是 3.3.2.GA 而 spring 是 3.1.1.RELEASE。设置如下:
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<mapping-file>persistence-query.xml</mapping-file>
...
<properties>
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.ejb.interceptor" value="com.myproj.common.dao.AuditInterceptor"/>
</properties>
</persistence-unit>
应用上下文:
<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"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="..."/>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:aspectj-autoproxy/>
<bean id="applicationContextProvder" class="com.myproj.common.utils.ApplicationContextProvider"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="myUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<!-- Local transaction management -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
和我的拦截器:
@Component
public class AuditInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 98658932451L;
@Autowired
private JdbcTemplate jdbcTemplate;
public void afterTransactionBegin(Transaction tx) {
if (user != null) {
jdbcTemplate.execute("call ah_audit_pkg.SetAudit('test')");
super.afterTransactionBegin(tx);
}
}
}
我 运行 一个 junit 来测试拦截器是否被调用。在调试模式下,我可以看到:
感谢任何帮助!为什么我的 intercetprot 没有被调用。
编辑:
我也试过拦截器覆盖 afterTransactionBegin 但它没有帮助。
我最终得到了以下解决方案:
我有一个从超级 class 映射实体延伸的实体:
@Entity
@Table(name = "my_table")
public class MyTable extends AuditInfo
AuditInfo
实体具有以下映射:
@MappedSuperclass
public abstract class AuditInfo implements Serializable {
...
@PrePersist
void onCreate() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is stored
}
@PreUpdate
void onPersist() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is updated
}
@PreRemove
void onRemove() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is removed
}
}
看点class:
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.mypackage.entities.AuditInfo.on*(..))")
public void setAuditHistory(JoinPoint jp){
final AuditInfo info = ((AuditInfo)jp.getThis());
JdbcTemplate jdbcTemplate = ApplicationContextProvider.getApplicationContext().getBean(JdbcTemplate.class);
jdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection conn) throws SQLException {
CallableStatement stmt = conn.prepareCall("begin ah_audit_pkg.SetAudit(?,?); end;");
stmt.setString(1, info.getAuditUser());
if(info.getAuditLocation() != null && info.getAuditLocation().trim().length() !=0) {
stmt.setString(2, info.getAuditLocation());
} else {
stmt.setString(2, info.getAuditUser());
}
return stmt;
}
}, new CallableStatementCallback<Object>() {
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
return cs.executeUpdate();
}
});
}
}
需要注意的是,Spring beans 是从上下文中提取的,而不是自动装配的 - 这是因为 AOP 在 spring 实现中是单例 class,并且 none 的自动装配 bean 将永远被实例化,即使它们在上下文中可用。所以我不得不手动检索它们以备后用。
设置我有一个旧项目坚持jdk 1.5,因此spring和hibernate版本也是支持此版本java的最大可能。 Hibernate 是 3.3.2.GA 而 spring 是 3.1.1.RELEASE。设置如下:
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<mapping-file>persistence-query.xml</mapping-file>
...
<properties>
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.ejb.interceptor" value="com.myproj.common.dao.AuditInterceptor"/>
</properties>
</persistence-unit>
应用上下文:
<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"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="..."/>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:aspectj-autoproxy/>
<bean id="applicationContextProvder" class="com.myproj.common.utils.ApplicationContextProvider"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="myUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<!-- Local transaction management -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
和我的拦截器:
@Component
public class AuditInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 98658932451L;
@Autowired
private JdbcTemplate jdbcTemplate;
public void afterTransactionBegin(Transaction tx) {
if (user != null) {
jdbcTemplate.execute("call ah_audit_pkg.SetAudit('test')");
super.afterTransactionBegin(tx);
}
}
}
我 运行 一个 junit 来测试拦截器是否被调用。在调试模式下,我可以看到:
感谢任何帮助!为什么我的 intercetprot 没有被调用。
编辑:
我也试过拦截器覆盖 afterTransactionBegin 但它没有帮助。
我最终得到了以下解决方案: 我有一个从超级 class 映射实体延伸的实体:
@Entity
@Table(name = "my_table")
public class MyTable extends AuditInfo
AuditInfo
实体具有以下映射:
@MappedSuperclass
public abstract class AuditInfo implements Serializable {
...
@PrePersist
void onCreate() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is stored
}
@PreUpdate
void onPersist() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is updated
}
@PreRemove
void onRemove() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is removed
}
}
看点class:
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.mypackage.entities.AuditInfo.on*(..))")
public void setAuditHistory(JoinPoint jp){
final AuditInfo info = ((AuditInfo)jp.getThis());
JdbcTemplate jdbcTemplate = ApplicationContextProvider.getApplicationContext().getBean(JdbcTemplate.class);
jdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection conn) throws SQLException {
CallableStatement stmt = conn.prepareCall("begin ah_audit_pkg.SetAudit(?,?); end;");
stmt.setString(1, info.getAuditUser());
if(info.getAuditLocation() != null && info.getAuditLocation().trim().length() !=0) {
stmt.setString(2, info.getAuditLocation());
} else {
stmt.setString(2, info.getAuditUser());
}
return stmt;
}
}, new CallableStatementCallback<Object>() {
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
return cs.executeUpdate();
}
});
}
}
需要注意的是,Spring beans 是从上下文中提取的,而不是自动装配的 - 这是因为 AOP 在 spring 实现中是单例 class,并且 none 的自动装配 bean 将永远被实例化,即使它们在上下文中可用。所以我不得不手动检索它们以备后用。