Я пытаюсь реализовать кеш, который содержит результаты определенного вызова бизнес-метода, а затем обновляется каждые 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: В случае, если это не достаточно ясно, мне нужно получить доступ к информации о invoker класс перехваченного метода, а не вызванный класс, у которого его метод перехвачен;вот почему я перебираю трассировку стека для доступа к классу вызывающего, но считаю, что это не элегантное решение, даже если оно работает.