javascript
Spring和Hibernate的自定义审核日志
如果您需要對所有數(shù)據(jù)庫操作進(jìn)行自動審核 ,并且正在使用Hibernate…,則應(yīng)使用Envers或spring data jpa auditing 。 但是,如果由于某些原因您不能使用Envers,則可以使用休眠事件偵聽器和spring事務(wù)同步來實(shí)現(xiàn)類似的功能。
首先,從事件監(jiān)聽器開始。 您應(yīng)該捕獲所有插入,更新和刪除操作。 但是有一點(diǎn)棘手的問題–如果出于某種原因需要刷新會話,則無法直接使用傳遞給事件偵聽器的會話執(zhí)行該邏輯。 以我為例,我必須獲取一些數(shù)據(jù),然后休眠開始向我拋出異常(“ id為null”)。 多個來源確認(rèn)您不應(yīng)在事件偵聽器中與數(shù)據(jù)庫進(jìn)行交互。 因此,您應(yīng)該存儲事件以供以后處理。 您可以將偵聽器注冊為spring bean ,如下所示 。
@Component public class AuditLogEventListenerimplements PostUpdateEventListener, PostInsertEventListener, PostDeleteEventListener {@Overridepublic void onPostDelete(PostDeleteEvent event) {AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);if (audited != null) {AuditLogServiceData.getHibernateEvents().add(event);}}@Overridepublic void onPostInsert(PostInsertEvent event) {AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);if (audited != null) {AuditLogServiceData.getHibernateEvents().add(event);}}@Overridepublic void onPostUpdate(PostUpdateEvent event) {AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);if (audited != null) {AuditLogServiceData.getHibernateEvents().add(event);}}@Overridepublic boolean requiresPostCommitHanding(EntityPersister persister) {return true; // Envers sets this to true only if the entity is versioned. So figure out for yourself if that's needed} }注意AuditedEntity –這是一個自定義標(biāo)記注釋(retention = runtime,target = type),您可以將其放置在實(shí)體之上。
老實(shí)說,我沒有完全了解Envers如何進(jìn)行持久化 ,但是由于我也可以使用spring,因此在AuditLogServiceData類中,我決定使用spring:
/*** {@link AuditLogServiceStores} stores here audit log information It records all * changes to the entities in spring transaction synchronizaton resources, which * are in turn stored as {@link ThreadLocal} variables for each thread. Each thread * /transaction is using own copy of this data.*/ public class AuditLogServiceData {private static final String HIBERNATE_EVENTS = "hibernateEvents";@SuppressWarnings("unchecked")public static List<Object> getHibernateEvents() {if (!TransactionSynchronizationManager.hasResource(HIBERNATE_EVENTS)) {TransactionSynchronizationManager.bindResource(HIBERNATE_EVENTS, new ArrayList<>());}return (List<Object>) TransactionSynchronizationManager.getResource(HIBERNATE_EVENTS);}public static Long getActorId() {return (Long) TransactionSynchronizationManager.getResource(AUDIT_LOG_ACTOR);}public static void setActor(Long value) {if (value != null) {TransactionSynchronizationManager.bindResource(AUDIT_LOG_ACTOR, value);}} }除了存儲事件之外,我們還需要存儲執(zhí)行操作的用戶。 為了做到這一點(diǎn),我們需要提供一個方法-參數(shù)級注釋來指定一個參數(shù)。 在我的案例中,注釋稱為AuditLogActor (保留=運(yùn)行時,類型=參數(shù))。
現(xiàn)在剩下的將是處理事件的代碼。 我們想在提交當(dāng)前事務(wù)之前執(zhí)行此操作。 如果提交后事務(wù)失敗,則審計條目插入也將失敗。 我們通過一點(diǎn)AOP來做到這一點(diǎn):
@Aspect @Component class AuditLogStoringAspect extends TransactionSynchronizationAdapter {@Autowiredprivate ApplicationContext ctx; @Before("execution(* *.*(..)) && @annotation(transactional)")public void registerTransactionSyncrhonization(JoinPoint jp, Transactional transactional) {Logger.log(this).debug("Registering audit log tx callback");TransactionSynchronizationManager.registerSynchronization(this);MethodSignature signature = (MethodSignature) jp.getSignature();int paramIdx = 0;for (Parameter param : signature.getMethod().getParameters()) {if (param.isAnnotationPresent(AuditLogActor.class)) {AuditLogServiceData.setActor((Long) jp.getArgs()[paramIdx]);}paramIdx ++;}}@Overridepublic void beforeCommit(boolean readOnly) {Logger.log(this).debug("tx callback invoked. Readonly= " + readOnly);if (readOnly) {return;}for (Object event : AuditLogServiceData.getHibernateEvents()) {// handle events, possibly using instanceof}}在我的情況下,我必須注入其他服務(wù),并且spring抱怨相互依賴的bean,所以我改用了applicationContext.getBean(FooBean.class) 。 注意:確保您的方面被Spring所捕獲–通過自動掃描,或通過xml / java-config顯式注冊它。
因此,已審核的呼叫將如下所示:
@Transactional public void saveFoo(FooRequest request, @AuditLogActor Long actorId) { .. }總結(jié)一下:休眠事件監(jiān)聽器將所有插入,更新和刪除事件存儲為spring事務(wù)同步資源。 一個方面用spring注冊一個事務(wù)“回調(diào)”,在提交每個事務(wù)之前立即調(diào)用它。 在那里處理所有事件,并插入相應(yīng)的審核日志條目。
這是非常基本的審核日志,可能在收集處理方面有問題,并且當(dāng)然不能涵蓋所有用例。 但這比手動審核日志處理要好得多,并且在許多系統(tǒng)中,審核日志是強(qiáng)制性功能。
翻譯自: https://www.javacodegeeks.com/2016/07/custom-audit-log-spring-hibernate.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的Spring和Hibernate的自定义审核日志的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 将电脑系统改成点歌系统(点歌机的系统可以
- 下一篇: 如何查询ip地址如何查询路由器内网ip