2011-10-03 38 views
0

爲了使用事件只有在交易成功聽了還是失敗,我下面講的事務觀察員定文檔: http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e4075事務性@observes是否在JBoss AS 7上觸發事件?

...但不能管理,使在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有問題,但是我找不到任何關於它的bug報告。

回答

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

該行爲不完全是提供本地@Observes(during=...)的行爲。完成後,部分沒有基於事務的狀態,但在自己的方法調用成功:

  • 在JaveEE6,成功後或失敗階段必須立即調用後,如果你在一個事務不是事務觀察家,就像IN_PROGRESS會做的。
  • 在此變通方法中,成功後或失敗階段後的觀察者將始終在方法結束時調用,並且僅在成功或失敗時調用。
0

這與版本7.1.0.Final一起工作,據稱( - >與Jboss你永遠不知道)完全符合Java EE。此外,您的bean不是線程安全的,因爲它使用list而不是併發隊列。

+0

好吧,我們會嘗試在7.1.0當縫面將由成功納入它(有一個關於它的問題是阻止我們)。另外,我認爲我的bean可以使用'List'並且是線程不安全的,因爲它是'@ RequestScoped'。 –

+0

對不起,延遲迴復。我發現焊接規範「定義」了關於觀察者方法的事務上下文的未定義行爲,用於「過期」屬性的某些值。似乎即使從控制流程的角度來看,交易應該仍然可用,但事實並非如此。將觀察者方法聲明爲需要事務處理的技巧。 – bennidi