好吧,由于我当前的测试让我认为事务性观察者无法在 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
。
该行为不完全是提供 native 的行为@Observes(during=...)
。after completion部分不是基于事务状态,而是基于你自己的方法调用成功:
- 在 JaveEE6 中,如果您不在事务中,则必须立即调用成功后或失败后阶段的事务观察器,就像
IN_PROGRESS
会做的那样。
- 在此解决方法中,成功或失败后阶段的观察者将始终在方法结束时被调用,并且仅在它成功或失败时才被调用。