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 将永远被实例化,即使它们在上下文中可用。所以我不得不手动检索它们以备后用。