亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Java CDI 攔截器中獲取調用者類

在 Java CDI 攔截器中獲取調用者類

蠱毒傳說 2024-01-05 15:00:33
我正在嘗試實現一個緩存,該緩存保存特定業務方法調用的結果,然后每 30 分鐘刷新一次。我能夠通過使用調度方法使用單例 EJB 來實現這一點;但是,現在每個調用該業務方法的類都必須從公開緩存結果的單例中調用方法。我想避免這種行為并保持這些類中的代碼不變,因此我想到使用一個攔截器來攔截對該特定業務方法的每個調用,并返回緩存單例的結果。但是,此解決方案會導致應用程序停止,因為單例調用攔截的業務方法本身來緩存其結果,因此攔截器會攔截該調用(請原諒重復)并嘗試返回公開緩存值的單例方法的結果,而單例仍在等待對業務方法的調用繼續進行。最明顯的解決方案是從攔截器中獲取方法調用者,并檢查其類是否對應于單例;如果是,則繼續調用,否則返回單例的緩存結果。但是,攔截器使用的對象似乎InvocationContext沒有公開任何方法來訪問有關被攔截方法的調用者的信息。有沒有其他方法可以訪問調用者的類,或者有解決此問題的方法嗎?這是我的單例類:@Singleton@Startuppublic class TopAlbumsHolder {    private List<Album> topAlbums;    @Inject    private DataAgent dataAgent;    @PostConstruct    @Schedule(hour = "*", minute = "*/30", persistent = false)    private void populateCache() {        this.topAlbums = this.dataAgent.getTopAlbums();    }    @Lock(LockType.READ)    public List<Album> getTopAlbums() {        return this.topAlbums;    }}這是我的攔截器:@Interceptor@Cacheable(type = "topAlbums")public class TopAlbumsInterceptor {    @Inject    private TopAlbumsHolder topAlbumsHolder;    @AroundInvoke    public Object interceptTopAlbumsCall(InvocationContext invocationContext) throws Exception {        // if the caller's class equals that of the cache singleton, then return invocationContext.proceed();         // otherwise:        return this.topAlbumsHolder.getTopAlbums();    }}請注意,該@Cacheable注釋是自定義攔截器綁定,而不是javax.persistence.Cacheable.編輯:我這樣修改了攔截器方法:@AroundInvokepublic Object interceptTopAlbumsCall(InvocationContext invocationContext) throws Exception {    for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace())        if (TopAlbumsHolder.class.getName().equals(stackTraceElement.getClassName()))            return invocationContext.proceed();    return this.topAlbumsHolder.getTopAlbums();}但我懷疑這是最干凈的解決方案,而且我不知道它是否便攜。編輯2:如果還不夠清楚,我需要訪問有關被攔截方法的調用者類的信息,而不是訪問其方法被攔截的被調用類的信息;這就是為什么我要迭代堆棧跟蹤來訪問調用者的類,但我認為這不是一個優雅的解決方案,即使它有效。
查看完整描述

3 回答

?
飲歌長嘯

TA貢獻1951條經驗 獲得超3個贊

對于你需要做的事情,我會說使用攔截器或裝飾器。然而你的攔截器是錯誤的。首先,您缺少基本部分,即對將調用InvocationContext.proceed()轉發給下一個內聯攔截器(如果有)或方法調用本身的調用。其次,您放置在那里的注入點非常具體,只有在攔截這種類型的 bean 時才會對您有所幫助。通常,周圍調用攔截器方法如下所示:


    @AroundInvoke

    Object intercept(InvocationContext ctx) throws Exception {

        // do something before the invocation of the intercepted method

        return ctx.proceed(); // this invoked next interceptor and ultimately the intercepted method

        // do something after the invocation of the intercepted method

    }

此外,如果您想要有關攔截哪個 bean 的元數據信息,每個攔截器都可以為此注入一個特殊的內置 bean。從元數據中,您可以收集有關當前正在攔截的 bean 的信息。以下是獲取元數據的方法:


    @Inject

    @Intercepted

    private Bean<?> bean;

請注意,攔截器不知道它們攔截的類型,它可以是任何類型,因此您通常需要對普通的進行操作Object。如果您需要更具體的東西,CDI 提供了一個裝飾器模式,它基本上是一個類型感知攔截器。它有一個特殊的注入點(委托),可以讓您直接訪問修飾的 bean。它可能更適合您的場景,請查看CDI 規范解釋裝飾器的這一部分。


查看完整回答
反對 回復 2024-01-05
?
慕容3067478

TA貢獻1773條經驗 獲得超3個贊

迭代堆棧跟蹤來檢查TopAlbumsHolder是否存在并不是一個好方法。為了避免在調用from類
期間調用攔截器,您可以直接在收集數據并將其推送到 中指定調度程序。您可以采用另一種方式,但您的要點是直接調用DataAgent bean 內的而不參與代理(在這種情況下,攔截器將不適用)。getTopAlbums()DataAgentDataAgentTopAlbumsHoldergetTopAlbums()

PS 請注意,緩存的數據應該是不可變的(集合及其對象)。


查看完整回答
反對 回復 2024-01-05
?
慕村225694

TA貢獻1880條經驗 獲得超4個贊

有一個誤會。您不將被攔截的對象注入到攔截器中,而是使用調用上下文。只需調用即可invocationContext.proceed(),無需遞歸。您可以緩存proceed() 的結果。



查看完整回答
反對 回復 2024-01-05
  • 3 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號