如何将 spring repo 注入休眠拦截器
How to inject spring repo into hibernate interceptor
我们正在构建一个应用程序,我们需要将实体更新记录到历史记录中 table。我正在尝试通过休眠拦截器来实现这一点,我们能够设法获得所有更改,但很难将它们插入审计 table。
我的 JPA 配置
public class JPAConfiguration {
----
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws SQLException {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] {"com.yyy.persist"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
// thsi is required in order to enable Query DSL
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
factoryBean.setJpaVendorAdapter(vendorAdapter);
// factoryBean.setMappingResources(mappingResources);
// adding hibernate interceptor
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.ejb.interceptor", "com.yyy.admin.service.AuditInterceptor");
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
我的拦截器
public class AuditInterceptor extends EmptyInterceptor {
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
if ( entity instanceof Auditable ) {
// updates++;
for (int i = 0; i < propertyNames.length; i++) {
if ((currentState[i] == null && previousState[i] != null)
|| (currentState[i] != null && previousState[i] == null) || (currentState[i] != null
&& previousState[i] != null && !currentState[i].equals(previousState[i]))) {
AuditLog audit = new AuditLog();
audit.setAction("UPDATE");
audit.setFieldChanged(propertyNames[i]);
audit.setOldvalue(previousState[i] != null ? previousState[i].toString() : "");
audit.setNewvalue(currentState[i] != null ? currentState[i].toString() : "");
audit.setTimeStamp(new Date());
audit.setUsername(userName);
entities.add(audit);
}
}
// iterate elements on the report build a entity
}
return false;
}
public void afterTransactionCompletion(Transaction tx) {
if (tx.wasCommitted()) {
if (entities != null) {
for (AuditLog e : entities) {
System.out.println(e);
//.save(e);
}
entities = new ArrayList<AuditLog>();
}
}
}
}
在 afterTransactionCompletion 方法中,我需要将所有审计实体写入数据库,Autowire 无法正常工作,因为这不是 spring 托管 bean,有没有办法在此方法中获取数据库会话,以便我可以执行插入.?
将 Spring Beans 注入非 spring 托管 class 的典型解决方案是通过 静态资源持有者 。例如,您有一个名为 StaticServiceHolder 的 class 并且使用 @Component
进行注释,然后为要通过 setter 注入的 spring bean 创建静态字段。喜欢:
@Component
public class StaticServiceHolder
{
public static AuditService auditService;
@Autowired
public void setAuditService(AuditService auditService)
{
StaticServiceHolder.auditService = auditService;
}
}
或者如果你有很多这些东西需要注入,那么更容易,然后你可以自动装配 ApplicationContext
。这样你就可以获得你需要的任何bean。
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) {
ApplicationContextHolder.applicationContext = ctx;
}
}
....
//in your hibernate interceptor
YourAuditService auditService = ApplicationContextHolder.applicationContext.getBean(YourAuditService.class);
auditService.saveAuditLog();
无论哪种方式,只要您使用的服务是 Transactional
,您就应该能够将您的内容保存在数据库中。希望这对你有用。
对于事务管理器设置:
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
我知道这有点晚了,但可能对其他人有帮助。
通过使用 spring bean 而不是 class 名称作为 "hibernate.ejb.interceptor"
的值,hibernate 使用 spring bean 而不是实例化新的 class.
更多信息可在此处找到:
Autowired to hibernate Interceptor
我们正在构建一个应用程序,我们需要将实体更新记录到历史记录中 table。我正在尝试通过休眠拦截器来实现这一点,我们能够设法获得所有更改,但很难将它们插入审计 table。
我的 JPA 配置
public class JPAConfiguration {
----
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws SQLException {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] {"com.yyy.persist"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
// thsi is required in order to enable Query DSL
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
factoryBean.setJpaVendorAdapter(vendorAdapter);
// factoryBean.setMappingResources(mappingResources);
// adding hibernate interceptor
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.ejb.interceptor", "com.yyy.admin.service.AuditInterceptor");
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
我的拦截器
public class AuditInterceptor extends EmptyInterceptor {
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
if ( entity instanceof Auditable ) {
// updates++;
for (int i = 0; i < propertyNames.length; i++) {
if ((currentState[i] == null && previousState[i] != null)
|| (currentState[i] != null && previousState[i] == null) || (currentState[i] != null
&& previousState[i] != null && !currentState[i].equals(previousState[i]))) {
AuditLog audit = new AuditLog();
audit.setAction("UPDATE");
audit.setFieldChanged(propertyNames[i]);
audit.setOldvalue(previousState[i] != null ? previousState[i].toString() : "");
audit.setNewvalue(currentState[i] != null ? currentState[i].toString() : "");
audit.setTimeStamp(new Date());
audit.setUsername(userName);
entities.add(audit);
}
}
// iterate elements on the report build a entity
}
return false;
}
public void afterTransactionCompletion(Transaction tx) {
if (tx.wasCommitted()) {
if (entities != null) {
for (AuditLog e : entities) {
System.out.println(e);
//.save(e);
}
entities = new ArrayList<AuditLog>();
}
}
}
}
在 afterTransactionCompletion 方法中,我需要将所有审计实体写入数据库,Autowire 无法正常工作,因为这不是 spring 托管 bean,有没有办法在此方法中获取数据库会话,以便我可以执行插入.?
将 Spring Beans 注入非 spring 托管 class 的典型解决方案是通过 静态资源持有者 。例如,您有一个名为 StaticServiceHolder 的 class 并且使用 @Component
进行注释,然后为要通过 setter 注入的 spring bean 创建静态字段。喜欢:
@Component
public class StaticServiceHolder
{
public static AuditService auditService;
@Autowired
public void setAuditService(AuditService auditService)
{
StaticServiceHolder.auditService = auditService;
}
}
或者如果你有很多这些东西需要注入,那么更容易,然后你可以自动装配 ApplicationContext
。这样你就可以获得你需要的任何bean。
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) {
ApplicationContextHolder.applicationContext = ctx;
}
}
....
//in your hibernate interceptor
YourAuditService auditService = ApplicationContextHolder.applicationContext.getBean(YourAuditService.class);
auditService.saveAuditLog();
无论哪种方式,只要您使用的服务是 Transactional
,您就应该能够将您的内容保存在数据库中。希望这对你有用。
对于事务管理器设置:
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
我知道这有点晚了,但可能对其他人有帮助。
通过使用 spring bean 而不是 class 名称作为 "hibernate.ejb.interceptor"
的值,hibernate 使用 spring bean 而不是实例化新的 class.
更多信息可在此处找到: Autowired to hibernate Interceptor