我正在尝试实现一个缓存,该缓存保存特定业务方法调用的结果,然后每 30 分钟刷新一次。
我能够通过使用调度方法使用单例 EJB 来实现这一点;但是,现在每个调用该业务方法的类都必须从公开缓存结果的单例中调用方法。
我想避免这种行为并保持这些类中的代码不变,因此我想到使用一个拦截器来拦截对该特定业务方法的每个调用,并返回缓存单例的结果。
但是,此解决方案会导致应用程序停止,因为单例调用拦截的业务方法本身来缓存其结果,因此拦截器会拦截该调用(请原谅重复)并尝试返回公开缓存值的单例方法的结果,而单例仍在等待对业务方法的调用继续进行。
最明显的解决方案是从拦截器中获取方法调用者,并检查其类是否对应于单例;如果是,则继续调用,否则返回单例的缓存结果。但是,拦截器使用的对象似乎InvocationContext没有公开任何方法来访问有关被拦截方法的调用者的信息。有没有其他方法可以访问调用者的类,或者有解决此问题的方法吗?
这是我的单例类:
@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注释是自定义拦截器绑定,而不是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:如果还不够清楚,我需要访问有关被拦截方法的调用者类的信息,而不是访问其方法被拦截的被调用类的信息;这就是为什么我要迭代堆栈跟踪来访问调用者的类,但我认为这不是一个优雅的解决方案,即使它有效。
饮歌长啸
慕容3067478
慕村225694
相关分类