事务性@observe是否适用于JBoss AS 7上的被激活事件?

时间:2011-10-03 16:31:42

标签: events jboss observer-pattern jboss7.x

为了使用仅在事务成功或失败时监听的事件,我正在关注有关事务观察者的给定文档: 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
    }
}

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

我在GlassFish 3上尝试了相同的代码并且它完全有效,所以我猜JBoss AS 7存在问题,但我找不到任何关于它的错误报告。

3 个答案:

答案 0 :(得分:0)

好吧,由于我目前的测试让我觉得交易观察员不在JBoss AS 7中工作,我设法为感兴趣的人做了一个解决方法。

首先,我们需要限定符注释:ImmediateAfterFailureAfterSuccess

@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那样。
  • 在此变通方法中,成功后或失败后的观察者将始终在方法结束时调用,并且仅在成功或失败时调用。

答案 1 :(得分:0)

这适用于版本7.1.0.Final,它应该是完全符合Java EE的(与你永远不知道的Jboss一起使用)。此外,您的bean不是线程安全的,因为它使用列表而不是并发队列。

答案 2 :(得分:0)