0

为了使用仅在事务成功或失败时才侦听的事件,我正在关注有关事务观察者的给定文档:http: //docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single /#d0e4075

...但无法使我的代码在 JBoss AS7 上运行。

这是我的 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
    }
}

这是我的基本听众:

public class MyHandler
{
    protected void listenMyEvent(@Observes(during=TransactionPhase.AFTER_SUCCESS) MyEvent event)
    {
        // do stuff
    }

    protected void listenMyEvent2(@Observes(during=TransactionPhase.AFTER_FAILURE) MyEvent event)
    {
        // do stuff
    }
}

我可以说我在触发事件时处于事务中,因为afterSave调用了 EJB 的方法。唉,方法listenMyEventlistenMyEvent2总是被调用,就像我不在事务环境中一样。

我在 GlassFish 3 上尝试了相同的代码,它运行良好,所以我猜 JBoss AS 7 存在问题,但我找不到任何关于它的错误报告。

4

3 回答 3

0

这适用于版本 7.1.0.Final,据说(-> 使用 Jboss 你永远不知道)完全兼容 Java EE。此外,您的 bean 不是线程安全的,因为它使用列表而不是并发队列。

于 2012-02-17T14:19:20.297 回答
0

您的观察者方法需要 REQUIRES_NEW,如此处所述:

http://www.seamframework.org/Documentation/WhyIsThereNoActiveTransactionInMySFSBTransactionalObserver

于 2012-07-02T09:04:24.153 回答
0

好吧,由于我当前的测试让我认为事务性观察者无法在 JBoss AS 7 中工作,因此我设法为感兴趣的人提供了一个解决方法。

首先,我们需要限定符注解:Immediate,AfterFailureAfterSuccess.

@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会做的那样。
  • 在此解决方法中,成功或失败后阶段的观察者将始终在方法结束时被调用,并且仅在它成功或失败时才被调用。
于 2011-10-11T11:40:06.603 回答