Events 事务性@observes是否适用于JBoss AS 7上的触发事件?
为了仅在事务成功或失败时使用侦听的事件,我遵循给定的关于事务观察者的文档: 。。。但是我无法使我的代码在JBossAS7上工作 这是我的EJB:Events 事务性@observes是否适用于JBoss AS 7上的触发事件?,events,jboss,observer-pattern,jboss7.x,Events,Jboss,Observer Pattern,Jboss7.x,为了仅在事务成功或失败时使用侦听的事件,我遵循给定的关于事务观察者的文档: 。。。但是我无法使我的代码在JBossAS7上工作 这是我的EJB: @LocalBean @Stateful @TransactionAttribute(TransactionAttributeType.NEVER) public class MyController { @Inject private transient Event<MyEvent> myEventLauncher;
@LocalBean
@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class MyController
{
@Inject
private transient Event<MyEvent> myEventLauncher;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save()
{
myEventLauncher.fire(new MyEvent());
}
@AfterCompletion
protected void afterSave(boolean isCommitted)
{
// do stuff
}
}
我可以说触发事件时我正在事务中,因为EJB的afterSave
方法被调用。唉,方法listenMyEvent
和listenMyEvent2
总是同时调用,就像我不在事务上下文中一样
我在GlassFish 3上尝试了相同的代码,它非常有效,所以我猜JBoss AS 7有问题,但我找不到任何关于它的错误报告。好吧,因为我当前的测试让我觉得事务性观察器在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
,用于在运行时创建这三个注释的实例
然后,我们需要一个用于真实事件的封装器,我将其命名为specialvent
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
公共类SpecialEventObserver
{
@注入
私有事件anyEventFirer;//真实事件的firer
私有列表事件;//排队事件
公共SpecialEventObserver()
{
事件=新的ArrayList();
}
//删除所有排队事件
公共无效重置()
{
this.events.clear();
}
public void fireAfterFailureEvents()引发异常
{
这个.firealleventsone(新的AfterFailureLiteral());
}
public void fireAfterSuccessEvents()引发异常
{
this.firealleventsone(新的AfterSuccessLiteral());
}
受保护的void ListensSpecialEvent(@Observes SpecialEvent SpecialEvent)
{
对象事件=specialEvent.getEvent();
this.events.add(事件);
这个.firevent(event,new immediateral());
}
受保护的void fireAllEventsOnce(注释限定符)引发异常
{
尝试
{
for(对象事件:this.events)
{
this.firevent(事件,限定符);
}
}
捕获(例外e)
{
投掷e;
}
最后
{
this.events.clear();
}
}
受保护的void fireEvent(对象事件、注释限定符)
{
Event-eventFirer=anyEventFirer.select(Event.getClass(),限定符);
eventFirer.fire(事件);
}
}
@拦截器
@局部感觉
公共类MyInterceptor实现可序列化
{
@注入
专用SpecialEventObserver SpecialEventObserver;
@阿隆登沃克
公共对象拦截(InvocationContext ic)引发异常
{
specialEventObserver.reset();
尝试
{
//调用实方法
Object proceedResult=ic.proceed();
//真实方法成功,发射成功事件
specialEventObserver.fireAfterSuccessEvents();
返回结果;
}
捕获(例外e)
{
//实方法失败,激发失败事件
specialEventObserver.fireAfterFailureEvents();
投掷e;
}
}
}
机制非常简单:
- 如果要触发事件,请触发保存真实事件的
SpecialEvent
将捕获任何SpecialEventObserver
,并将立即使用SpecialEvent
限定符触发您自己的事件。它还将对完成后部分的事件进行排队立即
- 在您自己的方法调用(
)结束时,ic.在拦截器中继续
将要求MyInterceptor
根据您方法的成功情况,使用SpecialEventObserver
限定符或失败后
限定符再次触发所有事件成功后
- 代替
,您自己的观察者必须使用正确的限定词来观察事件,如@Observes(during=…)
、@Observes@Immediate
或@Observes@AfterFailure
李>@Observes@AfterSuccess
@Observes(during=…)
的行为。完成后部分不是基于事务状态,而是基于您自己的方法调用成功:
- 在Javee6中,如果您不在事务中,则必须立即调用成功后或失败后阶段的事务观察器,就像进行中的
一样
- 在这个变通方法中,成功后或失败后阶段的观察者总是在方法结束时被调用,并且只有在方法成功或失败时才被调用李>
好吧,我们将在7.1.0上尝试,届时Seam Faces将成功包含在其中(有一个问题阻碍了我们)。另外,我认为我的bean可以使用
列表
,并且线程不安全,因为它是@RequestScoped
。很抱歉回复太晚。我发现weld规范“定义”了一个未定义的行为,该行为与观察者方法的事务上下文有关,用于“在”属性的某些值。看起来,即使从控制流的角度来看,一个事务应该仍然可用,它也不可用。将observer方法声明为需要一个事务就可以了。
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;
}
}
}