當前位置:
首頁 > 知識 > 定製Spring和Hibernate系統的審計Audit日誌

定製Spring和Hibernate系統的審計Audit日誌

如果你希望能夠對所有資料庫操作自動審計,推薦使用 Envers 或 spring data jpa auditing,但是如果因為一些原因不使用Envers,你可以使用Hibernate的事件監聽器和Spring事務同步機制完成類似審計日誌功能,本文主要演示這方面的技術。

使用事件監聽器,你能截獲所有的新增 修改和刪除操作,但是有一點技巧在裡面,如果你需要flush會話,你不能在事件監聽器中和資料庫交互,你應該存儲事件以便日後處理,你能註冊監聽器作為一個Spring bean如下:

@Component
public class AuditLogEventListener
implements PostUpdateEventListener, PostInsertEventListener, PostDeleteEventListener {
@Override
public void onPostDelete(PostDeleteEvent event) {
AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);
if (audited != null) {
AuditLogServiceData.getHibernateEvents().add(event);
}
}
@Override
public void onPostInsert(PostInsertEvent event) {
AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);
if (audited != null) {
AuditLogServiceData.getHibernateEvents().add(event);
}
}
@Override
public void onPostUpdate(PostUpdateEvent event) {
AuditedEntity audited = event.getEntity().getClass().getAnnotation(AuditedEntity.class);
if (audited != null) {
AuditLogServiceData.getHibernateEvents().add(event);
}
}

@Override
public 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是一個定製的marker元注釋(retention=runtime, target=type),你可以將它作為元注釋用在你的實體上面。

在下面AuditServiceData類使用Spring的事務機制進行持久化:

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);
}
}
}

為了存儲事件,我們也要存儲用戶執行的動作,為了能獲得這些,我們需要提供一個方法參數級別的元注釋來設計參數,這個元注釋稱為AuditLogActor(retention=runtime, type=parameter) 。

現在剩餘的是處理事件的代碼,我們要在提交當前事務之前實現事件存儲,如果事務失敗,審計輸入也會失敗,這裡使用AOP:

@Aspect
@Component
class AuditLogStoringAspect extends TransactionSynchronizationAdapter {
@Autowired
private 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 ++;
}
}
@Override
public 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
}
}

這裡注入另外的服務,需要激活Auto-scanning或顯式註冊到XML或Java-config中。

調用這個審計如下代碼:

@Transactional
public void saveFoo(FooRequest request, @AuditLogActor Long actorId) { .. }

總結:Hibernate的事件監聽器存儲所有插入 更新和刪除事件作為Spring事務同步資源,一個aspect註冊器是帶有事務回調的Spring類,能夠在事務提交之前被調用,當有操作事件發生時,響應的審計日誌會新增一個記錄。

定製Spring和Hibernate系統的審計Audit日誌

打開今日頭條,查看更多圖片
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

Tensorflow_08A_Keras 助攻下的 Sequential 模型
配置 redis 外網可訪問

TAG:程序員小新人學習 |