Я некоторое время искал решение той же проблемы в Java EE. Я просмотрел Axon и jdon (страница тоже не сулит ничего хорошего :)). Оба связаны с Event Sourcing, которые я не мог «продать» своим работодателям/клиентам. Я хотел иметь события домена, так как я очень привык к ним в проектах .NET/C#. Итак, я пришел к следующему...
Я использовал аналогичный статический объект DomainEvents, чтобы предоставить мне доступ к механизму публикации без фактической утечки сведений о реализации во всех объектах модели предметной области. Итак, звонки примерно такие:
DomainEvents.fire(new MySampleEvent(...some params...));
Шаблон и механизм, доступные в спецификации CDI, — это События с @Observes которые позволяют вам реагировать на определенные события в обычных bean-компонентах со всеми доступными службами. Это похоже на то, к чему я привык при использовании DI-фреймворков, таких как Castle Windsor, где я может регистрировать универсальные обработчики по интерфейсу. Итак, у меня есть наблюдатели (обработчики, слушатели, называйте их как угодно). Пример:
@Stateless
public class MySampleEventObserver {
public void listen(@Observes MySampleEvent event) {
...
doSomethingWithEvent();
}
}
Теперь о публикации (запуске в CDI). Поскольку нет возможности получить доступ к CDI в сущностях (не без оснований!), я решил использовать JNDI и BeanManager. Я использовал JNDI, чтобы получить BeanManager и использовать его метод fireEvent. Чтобы поместить разрешение bean-менеджера (как см. здесь) в коде:
public class BeanHelper {
public static BeanManager getBeanManager() {
try {
InitialContext initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
}
Последним шагом является сам объект DomainEvents:
public class DomainEvents {
private static boolean mNopMode = false;
public static void setNopMode() {
mNopMode = true;
}
public static void reset() {
mNopMode = false;
}
public static <TDomainEvent> void fire(TDomainEvent event) {
if (mNopMode) {
return;
}
BeanManager manager = BeanHelper.getBeanManager();
manager.fireEvent(event);
}
}
Части setNopMode
и reset
предназначены для тестирования, когда нет контекста. Ручное издевательство в основном. Установите его в режим работы NOP перед юнит-тестами и сбросьте после них.
Отлично работает как POC. Не знаю, есть ли какие-то серьезные ограничения на его использование. Я оставляю асинхронные взаимодействия шины и аналогичную реализацию слушателей.
Буду рад любым комментариям.
person
jl.
schedule
12.04.2013