Events 事务性@observes是否适用于JBoss AS 7上的触发事件?

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;

为了仅在事务成功或失败时使用侦听的事件,我遵循给定的关于事务观察者的文档:

。。。但是我无法使我的代码在JBossAS7上工作

这是我的EJB:

@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.Final版本,该版本被认为(->适用于您永远不知道的Jboss)完全兼容Java EE。此外,您的bean不是线程安全的,因为它使用列表而不是并发队列。

您的观察者方法需要新的,如下所述:


好吧,我们将在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;
        }
    }
}