gpt4 book ai didi

java - 在 Java CDI 拦截器中获取调用者类

转载 作者:行者123 更新时间:2023-12-02 09:22:34 27 4
gpt4 key购买 nike

我正在尝试实现一个缓存,该缓存保存特定业务方法调用的结果,然后每 30 分钟刷新一次。

我能够通过使用调度方法使用单例 EJB 来实现这一点;但是,现在每个调用该业务方法的类都必须从公开缓存结果的单例中调用方法。

我想避免这种行为并保持这些类中的代码不变,因此我考虑使用一个拦截器来拦截对该特定业务方法的每次调用,并返回缓存单例的结果。

但是,此解决方案会导致应用程序停止,因为单例调用被拦截的业务方法本身来缓存其结果,因此拦截器会拦截该调用(请原谅重复)并尝试返回公开缓存的单例方法的结果值,而单例仍在等待对业务方法的调用继续。

最明显的解决方案是从拦截器中获取方法调用者,并检查其是否类对应于单例;如果是,则继续调用,否则返回单例的缓存结果。但是,拦截器使用的 InitationContext 对象似乎没有公开任何方法来访问有关被拦截方法的调用者的信息。有没有其他方法来访问调用者的类,或者解决此问题?

这是我的单例类:

@Singleton
@Startup
public 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 注释是自定义拦截器绑定(bind),而不是 javax.persistence.Cacheable

编辑:我这样修改了拦截器方法:

@AroundInvoke
public 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:如果还不够清楚,我需要访问有关被拦截方法的invoker类的信息,而不是具有其方法的被调用类的信息拦截;这就是为什么我要迭代堆栈跟踪来访问调用者的类,但我认为这不是一个优雅的解决方案,即使它有效。

最佳答案

对于你需要做的事情,我建议使用拦截器或装饰器。然而你的拦截器是错误的。首先,您缺少基本部分,即对 InvocationContext.proceed() 的调用,它将调用转发给下一个内联拦截器(如果有)或方法调用本身。其次,您放置在那里的注入(inject)点非常具体,只有在拦截这种类型的 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 的元数据信息,每个拦截器都可以为此注入(inject)一个特殊的内置 bean。从元数据中,您可以收集有关当前正在拦截的 bean 的信息。以下是获取元数据的方法:

    @Inject
@Intercepted
private Bean<?> bean;

请注意,拦截器不知道它们拦截的类型,它可以是任何类型,因此您通常需要对普通的对象进行操作。如果您需要更具体的东西,CDI 提供了一个装饰器模式,它基本上是一个类型感知拦截器。它有一个特殊的注入(inject)点(委托(delegate)),可以让您直接访问修饰的 bean。它可能更适合您的场景,请查看 this part of CDI specification explaining Decorators .

关于java - 在 Java CDI 拦截器中获取调用者类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58583469/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com