Из обсуждения на форумах Glassfish:
Вставленная ссылка обновляется, только когда новый экземпляр, в который она вставлена, создается контейнером EJB. Так что, если вы будете искать его все время, вы получите экземпляр с обновленной ссылкой, но если ваш код будет привязан к исходному экземпляру или если он будет объединен в пул, введенная ссылка останется устаревшей.
Итак, корень проблемы в том, что ссылка на EJB - stale . Я нашел два решения этой проблемы:
- Поиск EJB при каждом запросе (не используйте CDI)
- Обернуть EJB в прокси, который ищет EJB, если ссылка устарела
Со вторым решением CDI все еще может использоваться. Вам понадобится продюсер и InvocationHandler
. Приведенный ниже код является упрощенной версией кода, который я использую в своем проекте, и он может не скомпилироваться должным образом, но он покажет идею и концепции, использованные при выполнении этой работы. YMMV.
Во-первых, в коде, который использует EJB, вы используете @Inject
следующим образом:
public class Foo {
@Inject
MyEjb obj;
}
Во-вторых, вам нужен продюсер, который просто возвращает упакованную версию EJB:
public class MyEjbProducer {
@EJB(name = "MyEjb")
private MyEjb obj;
@Produces
public MyEjb getEjb(final InjectionPoint ip) {
InvocationHandler handler = new MyInvocationHandler(obj, MyEjb.class);
return (MyEjb)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
В-третьих, обработчик вызова должен проверить на NoSuchEjbException
и снова найти компонент:
public class MyInvocationHandler implements InvocationHandler {
private MyEjb obj;
private Class lookupClass;
public MyInvocationHandler(MyEjb obj, Class lookupClass) {
this.obj = obj;
this.lookupClass = lookupClass;
}
public Object invoke (...) {
try {
return method.invoke(impl, args);
} catch (final InvocationTargetException e) {
if (e.getTargetException() instanceof NoSuchEJBException) {
// 1. look up EJB again
// 2. try calling invoke again
}
}
}
}
Этот код ни в коем случае не является полным. Часть кода, такая как поиск EJB и повторный вызов метода, была опущена.
Делать так будет работать. Другим методом было бы сделать нечто подобное, но добавить отдельный метод к EJB для проверки на устаревание вместо использования метода, который пользователь пытается вызвать.
Что ты думаешь? Есть ли лучшее решение?