91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Spring和Hibernate自定義審計日志

發布時間:2022-02-28 11:21:31 來源:億速云 閱讀:183 作者:小新 欄目:開發技術

這篇文章主要介紹如何使用Spring和Hibernate自定義審計日志,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

如果您需要對所有數據庫操作進行自動審計,并且您正在使用 Hibernate……您應該使用Enversspring data jpa auditing。但是如果由于某些原因您不能使用 Envers,您可以使用 hibernate 事件偵聽器和 spring 事務同步來實現類似的功能。

首先,從事件監聽器開始。您應該捕獲所有插入、更新和刪除操作。但是有一個棘手的問題——如果您出于任何原因需要刷新會話,則不能使用傳遞給事件偵聽器的會話直接執行該邏輯。在我的情況下,我必須獲取一些數據,并且 hibernate 開始向我拋出異常(“id 為 null”)。多個來源確認您不應在事件偵聽器中與數據庫交互。因此,您應該存儲事件以供以后處理。您可以將偵聽器注冊為 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- 它是一個自定義標記注釋(retention=runtime, target=type),您可以將其放在實體之上。

由于我有 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);
        }
    }
 
    public void clear() {
       // unbind all resources
    }
}

除了存儲事件之外,我們還需要存儲正在執行操作的用戶。為了得到它,我們需要提供一個方法參數級別的注釋來指定一個參數。在我的例子中的注釋被稱為AuditLogActor(retention=runtime, type=parameter)

現在剩下的是處理事件的代碼。我們希望在提交當前事務之前執行此操作。如果事務在提交時失敗,審計條目插入也將失敗。我們用一點 AOP 來做到這一點:

@Aspect
@Component
class AuditLogStoringAspectextends 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
        }
    }
 
    @Override
    public void afterCompletion(int status) {
    // we have to unbind all resources as spring does not do that automatically
        AuditLogServiceData.clear();
     }

就我而言,我不得不注入額外的服務,而 spring 抱怨相互依賴的 bean,所以我改為使用applicationContext.getBean(FooBean.class). 注意:確保您的方面被 spring 捕獲 - 通過自動掃描或通過 xml/java-config 顯式注冊它。

因此,經過審計的調用將如下所示:

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

總結一下:hibernate 事件監聽器將所有插入、更新和刪除事件存儲為 Spring 事務同步資源。一個方面向 spring 注冊一個事務“回調”,它在每個事務提交之前被調用。在那里處理所有事件并插入相應的審計日志條目。

這是非常基本的審計日志,它可能在收集處理方面存在問題,而且它肯定沒有涵蓋所有用例。但它比手動審計日志處理要好得多,并且在許多系統中,審計日志是強制性功能。

以上是“如何使用Spring和Hibernate自定義審計日志”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邯郸县| 汾阳市| 谢通门县| 衡南县| 屯门区| 怀远县| 嘉义市| 巴林右旗| 桐庐县| 沙洋县| 乳山市| 涟源市| 两当县| 南江县| 方城县| 漳州市| 安国市| 屯门区| 滁州市| 长泰县| 嘉峪关市| 沂南县| 马公市| 合江县| 鸡东县| 铜川市| 班玛县| 鹤岗市| 阳谷县| 锦屏县| 中卫市| 红桥区| 安吉县| 广昌县| 仙游县| 临清市| 苍南县| 通榆县| 泸水县| 红安县| 漳浦县|