【问题标题】:Injecting JPA's Entity Manager in Hibernate's EmptyInterceptor在 Hibernate 的 EmptyInterceptor 中注入 JPA 的实体管理器
【发布时间】:2013-10-13 14:45:55
【问题描述】:

我在数据访问层中使用 JPA-2.0 和 Hibernate。

出于审计日志记录的目的,我通过在 persistence.xml 中配置以下属性来使用 Hibernate 的 EmptyInterceptor:

<property name="hibernate.ejb.interceptor"  
                value="com.mycom.audit.AuditLogInterceptor" /> 

AuditLogInterceptor 扩展了 hibernate 的“org.hibernate.EmptyInterceptor”。

public class AuditLogInterceptor extends EmptyInterceptor {  

    private Long userId;  

    public AuditLogInterceptor() {}  

    @Override  
    public boolean onSave(Object entity, Serializable id, Object[] state,  
            String[] propertyNames, Type[] types) throws CallbackException {  
        // Need to perform database operations using JPA entity manager
        return false;  
    }  

   @Override
    public boolean onFlushDirty(Object entity, Serializable id,
            Object[] currentState, Object[] previousState,
            String[] propertyNames, Type[] types) {
        // other code here        
        return false;
    }

    @Override  
    public void postFlush(Iterator iterator) throws CallbackException {  
        System.out.println("I am on postFlush");
        // other code here 
    }  
}  

我在数据访问层使用 JPA 实体管理器来执行数据库操作。 JPA 配置如下:

<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        p:persistenceUnitName="PersistenceUnit"
        p:persistenceXmlLocation="classpath*:persistence.xml"
        p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
        <property name="loadTimeWeaver">
            <bean
                class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
    </bean>

我的 AbstractDAO 是:

public class AbstractDao<T, ID extends Serializable> {

    private final transient Class<T> persistentClass;

    protected transient EntityManager entityManager;

    @SuppressWarnings("unchecked")
    public AbstractDao() {

        this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @PersistenceContext
    public final void setEntityManager(final EntityManager entityMgrToSet) {

        this.entityManager = entityMgrToSet;
    }

    public final Class<T> getPersistentClass() {

        return persistentClass;
    }

    public final void persist(final T entity) {

         entityManager.persist(entity);       
    }

}

我想在“AuditLogInterceptor”中注入 JPA 实体管理器,以便像抽象 DAO 一样在“AuditLogInterceptor”中执行数据库操作。

有什么想法吗?正确的解决方案应该是什么?

【问题讨论】:

    标签: spring hibernate jpa-2.0 audit-logging


    【解决方案1】:

    我有一种简单的方法可以在“AuditLogInterceptor”中使用 JPA 实体管理器执行数据库操作

    我创建了下面的类,它将提供应用程序上下文参考:

    @Component("applicationContextProvider")
        public class ApplicationContextProvider implements ApplicationContextAware {
            private static ApplicationContext context;
    
            public static ApplicationContext getApplicationContext() {
                return context;
            }
    
            @Override
            public void setApplicationContext(ApplicationContext ctx) {
                context = ctx;
            }
        }
    

    创建的数据访问类:

    @Repository("myAuditDAO")
    public class myAuditDAO<T, ID extends Serializable> {
    
        private final transient Class<T> persistentClass;
    
        protected transient EntityManager entityManager;
    
        @SuppressWarnings("unchecked")
        public MyDAO() {
    
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
    
        @PersistenceContext
        public final void setEntityManager(final EntityManager entityMgrToSet) {
    
            this.entityManager = entityMgrToSet;
        }
    
        public final Class<T> getPersistentClass() {
    
            return persistentClass;
        }
    
        public final T findById(final ID theId) {
    
            return entityManager.find(persistentClass, theId);
        }
    
        public final void persist(final T entity) {
    
            entityManager.persist(entity);
        }
    
        public final void merge(final T entity) {
    
            entityManager.merge(entity);
        }
    }
    

    并在“AuditLogInterceptor”中使用“ApplicationContextProvider”来获取“MyAuditDAO”的引用,该引用将 JPA 实体管理器作为在 DAO 初始化期间注入的属性。现在在“MyAuditDAO”的帮助下,我可以执行数据库操作了。

    public class AuditLogInterceptor extends EmptyInterceptor {  
    
        @Override  
        public void postFlush(Iterator iterator) throws CallbackException {  
    
          // Here we can get the MyAuditDao reference and can perform persiste/merge options
           MyAuditDao myAuditDao = (MyAuditDao ) ApplicationContextProvider.getApplicationContext().getBean("myAuditDao");
    
          //  myAuditDao.persist(myEntity);
    
        }  
    } 
    

    【讨论】:

    • 我正在尝试在 JPA2 中执行此操作以获取对我的 auditLogRepository 的引用,因为使用 @Resource 注释没有注入任何内容,并给我留下了 NPE。
    【解决方案2】:

    我正在考虑在您的 Abstract 类中成功启动 persistenceManager。你可能有一个类AuditLogDAO,它扩展了你的AbstractDao。将 AuditLogDAO 类注入你的拦截器并调用auditLogDAO.save(entity); 和其他方法。

    或者编写一个 Util 类来执行数据库操作并将 util 类注入你的拦截器。

    【讨论】:

      猜你喜欢
      • 2016-03-24
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 2014-09-06
      • 2015-09-29
      • 1970-01-01
      • 2017-10-23
      • 1970-01-01
      相关资源
      最近更新 更多