Ну, так как мои текущие тесты заставили меня подумать, что в JBoss AS 7 не работают наблюдатели транзакций, мне удалось сделать обходной путь, который я дал здесь для людей, которые заинтересованы.
Во-первых, нам нужны аннотации классификатора: Immediate
, AfterFailure
и AfterSuccess
.
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
public @interface AfterFailure
{}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
public @interface AfterSuccess
{}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
public @interface Immediate
{}
Также три основных AnnotationLiteral
для создания во время выполнения экземпляров этих трех аннотаций.
Затем нам нужен инкапсулятор для наших истинных событий, который я назвал SpecialEvent
.
public class SpecialEvent
{
private Object event; // the real event you want
public SpecialEvent(Object event)
{
super();
this.event = event;
}
public Object getEvent()
{
return event;
}
}
И, наконец, наблюдатель для этого специального события и перехватчик для классов, где вы хотите запускать события такого типа (полное объяснение ниже).
@RequestScoped
public class SpecialEventObserver
{
@Inject
private Event<Object> anyEventFirer; // firer for real events
private List<Object> events; // queued events
public SpecialEventObserver()
{
events = new ArrayList<Object>();
}
// remove all queued events
public void reset()
{
this.events.clear();
}
public void fireAfterFailureEvents() throws Exception
{
this.fireAllEventsOnce(new AfterFailureLiteral());
}
public void fireAfterSuccessEvents() throws Exception
{
this.fireAllEventsOnce(new AfterSuccessLiteral());
}
protected void listenSpecialEvent(@Observes SpecialEvent specialEvent)
{
Object event = specialEvent.getEvent();
this.events.add(event);
this.fireEvent(event, new ImmediateLiteral());
}
protected void fireAllEventsOnce(Annotation qualifier) throws Exception
{
try
{
for (Object event : this.events)
{
this.fireEvent(event, qualifier);
}
}
catch (Exception e)
{
throw e;
}
finally
{
this.events.clear();
}
}
protected void fireEvent(Object event, Annotation qualifier)
{
Event eventFirer = anyEventFirer.select(event.getClass(), qualifier);
eventFirer.fire(event);
}
}
@Interceptor
@LocalInterception
public class MyInterceptor implements Serializable
{
@Inject
private SpecialEventObserver specialEventObserver;
@AroundInvoke
public Object intercept(InvocationContext ic) throws Exception
{
specialEventObserver.reset();
try
{
// call the real method
Object proceedResult = ic.proceed();
// real method succeeded, fire successful events
specialEventObserver.fireAfterSuccessEvents();
return proceedResult;
}
catch (Exception e)
{
// real method failed, fire failed events
specialEventObserver.fireAfterFailureEvents();
throw e;
}
}
}
Механизм довольно прост:
- Если вы хотите запустить событие, запустите
SpecialEvent
, который содержит истинное событие.
-
SpecialEventObserver
поймает любой SpecialEvent
и немедленно запустит ваше собственное событие с квалификатором Immediate
. Он также будет ставить в очередь события для части после завершения.
- В конце вашего собственного вызова метода (
ic.proceed
в перехватчике) MyInterceptor
попросит SpecialEventObserver
либо снова запустить все события с квалификатором AfterFailure
или AfterSuccess
, в зависимости от успех вашего метода.
- Вместо
@Observes(during=...)
ваши собственные наблюдатели должны наблюдать за событиями с подходящим квалификатором, таким как @Observes @Immediate
, @Observes @AfterFailure
или @Observes @AfterSuccess
.
Поведение не совсем то, которое обеспечивает нативное @Observes(during=...)
. Часть после завершения основана не на состоянии транзакции, а на собственном успехе вызова метода:
- В JaveEE6 наблюдатели транзакций, включенные после успешной или после неудачной фазы, должны быть немедленно вызваны, если вы не в транзакции, как это сделал бы
IN_PROGRESS
.
- В этом обходном пути наблюдатели, находящиеся на этапах после успеха или после сбоя, всегда будут вызываться в конце метода, и только в случае успеха или неудачи.