2014-02-22 5 views
11

Guava의 EventBus를 사용하여 일부 처리 및 결과보고를 시작합니다.Guava EventBus dispatching

import com.google.common.eventbus.EventBus; 
import com.google.common.eventbus.Subscribe; 

public class Test { 

    public static class InitiateProcessing { } 
    public static class ProcessingStarted { } 
    public static class ProcessingResults { } 
    public static class ProcessingFinished { } 

    public static EventBus bus = new EventBus(); 

    @Subscribe 
    public void receiveStartRequest(InitiateProcessing evt) { 
     System.out.println("Got processing request - starting processing"); 
     bus.post(new ProcessingStarted()); 

     System.out.println("Generating results"); 
     bus.post(new ProcessingResults()); 
     System.out.println("Generating more results"); 
     bus.post(new ProcessingResults()); 

     bus.post(new ProcessingFinished()); 
    } 

    @Subscribe 
    public void processingStarted(ProcessingStarted evt) { 
     System.out.println("Processing has started"); 
    } 

    @Subscribe 
    public void resultsReceived(ProcessingResults evt) { 
     System.out.println("got results"); 
    } 

    @Subscribe 
    public void processingComplete(ProcessingFinished evt) { 
     System.out.println("Processing has completed"); 
    } 


    public static void main(String[] args) { 
     Test t = new Test(); 
     bus.register(t); 
     bus.post(new InitiateProcessing()); 
    } 
} 

나는이 처리를 위해 준비에 반응하는 다른 소프트웨어 구성 요소에 대한 방법으로 이러한 이벤트를 사용 : 여기에 아주 간단한 컴파일 가능한 예입니다. 예를 들어 처리하기 전에 현재 상태를 저장 한 후 복원해야 할 수 있습니다.

나는이 프로그램의 출력이 될 기대

:

Got processing request - starting processing 
Processing has started 
Generating results 
got results 
Generating more results 
got results 
Processing has completed 

는 대신, 실제 출력은 다음과 같습니다

Got processing request - starting processing 
Generating results 
Generating more results 
Processing has started 
got results 
got results 
Processing has completed 

실제로 시작 후 발생했다 그 처리를 표시하도록되어 이벤트 실제 처리 ("결과 생성").

소스 코드를보고 나면 왜 이런 식으로 행동하는지 이해합니다. EventBus의 관련 source code은 다음과 같습니다. 이미 최상위 InitiateProcessing 이벤트, 단지 큐의 끝에 얻을수 이벤트의 나머지 부분을 파견하고있어 이후 무슨 일

/** 
    * Drain the queue of events to be dispatched. As the queue is being drained, 
    * new events may be posted to the end of the queue. 
    */ 
    void dispatchQueuedEvents() { 
    // don't dispatch if we're already dispatching, that would allow reentrancy 
    // and out-of-order events. Instead, leave the events to be dispatched 
    // after the in-progress dispatch is complete. 
    if (isDispatching.get()) { 
     return; 
    } 
    // dispatch event (omitted) 

이다. 모든 .NET 핸들러가 완료 될 때까지 이벤트를 호출하지 않는 .NET 이벤트와 비슷한 동작을하고 싶습니다.

이 구현에 대한 이유를 이해하지 못합니다. 물론 이벤트는 순서대로 보장되지만 주변 코드의 순서는 완전히 왜곡됩니다.

버스가 설명 된대로 작동하고 원하는 출력을 낼 수있는 방법이 있습니까? I는 Javadoc과의 EventBus이 방법은 명시 적으로 @AllowConcurrentEvents 주석을 함유하여 을 허용하지 않으면이 동시에 여러 스레드에서 가입자 메소드를 호출하지 않을 것이라는 보장

것을 읽었다.

하지만 여기서는 이것이 적용되지 않는다고 생각합니다. 단일 스레드 응용 프로그램에서이 문제를보고 있습니다.

편집

여기에 문제의 원인은 내가 가입자 내에서 보내고 post 해요 있다는 것입니다. 이벤트 버스는 재 입력이 아니므로 이러한 "하위 게시물"은 대기열에 올라서 첫 번째 처리기가 완료된 후에 처리됩니다. 내가섹션에서 언급 할 수 있으며, 모든 것이 예상대로 작동합니다. 그래서 실제 질문은 내가 제기 한 잠재적 인 문제점을 어떻게 알았습니까? 디자이너는 재진입을 허용하지 않기 위해 양심적 인 결정을 한 것 같습니다.

+0

은 이벤트 버스가 자체 스레드에서 실행되는 것처럼 보입니다. 즉, 액션은 비동기 적으로 수행되고 (곧 버스 임), 명령에 따라 전달되도록 보장되며 메인 스레드와 아무런 관련이 없음을 의미합니다. – injecteer

+0

@injecteer 자체 스레드를 실행하지 않습니다. 그들은 당신이'Executor'를 지정할 수있게 해주는'AsyncEventBus'를 가지고 있습니다 -하지만 그것을 사용하지는 않습니다. 이것은 모두 단일 스레드입니다. – zmb

+0

당신이 옳을 수도 있습니다. 내 생각에 그들은 새로운 스레드에서 실행한다 :) 당신은 각각의 처리에'System.out.println ("curr thread :"+ Thread.currentThread(). getName())' @ Subscribe'-d 메소드? – injecteer

답변

7

EventBus은 일반적으로 버스에 이벤트를 게시 코드가 가입자 이외의 사건이나 때, 함께 할 일에 대해 신경 안된다는 원리에 따라 작동하는 이벤트가 존경에 게시 된 순서 (에 어쨌든 동기 이벤트 버스의 경우).

메소드의 특정 시간에 특정 메소드가 호출되도록하고 메소드가 계속되기 전에 해당 메소드가 완료되도록하려면 (예에서와 같이) 해당 메소드를 직접 호출하지 마십시오. ? 이벤트 버스를 사용하면 명시된 이벤트에 대한 응답으로 코드가 명시 적으로 분리됩니다. 이것은 많은 경우에 바람직하며 주된 이유는 EventBus입니다. 그러나 당신이 여기서 원하는 것 같지는 않습니다. 모든 가입자에게 통지되며, 이벤트 E1이 순간 T1에 게시되어있는 경우

:

+0

"주어진 이벤트에 대한 응답으로 코드가 정확히 분리됩니다"*는 * 내가 원하는 것입니다.이벤트에서 "일이 생길 준비를하라"고 말하고 싶습니다. 가입자가 준비하기 위해 어떻게 또는 무엇을해야하는지 상관하지 않습니다. 그들은 아무 것도 할 필요가 없을 수도 있습니다. 이벤트를 게시 한 후 구독자가 준비가되어 있으므로 어떤 조치를 취할 수 있다고 확신하고 싶습니다. 이벤트 버스는 이벤트를 다르게 처리 할 수있는 구성 요소를 쉽게 추가하고 제거 할 수 있기 때문에이 경우에 완벽하게 보입니다. 이벤트를 게시하는 코드는 상관하지 않습니다. – zmb

+1

지금까지 답변에서 벗어난 것은이 동작이 의도적으로 설계된 것이며 이벤트 버스가 그대로 사용 사례를 지원하지 않는다는 것입니다. 나는 나의 유스 케이스에 더 잘 맞는 재진입을 허용하기 위해 버스를 수정하는 것을 끝내었다. – zmb

2

모든 "가입자"가 신호를받을 때까지 EventBus에 게시하는 것은 반환되지 않습니다. 이러한 가입자는 실행을 시작하지 않았을 수 있습니다. 즉, 첫 번째 bus.post가 반환 될 때 중간 구독자가 처리를 시작하지 않고 다음 게시물을 계속 진행한다는 의미입니다.

public void post (객체 이벤트) 등록 된 모든 가입자에게 이벤트를 게시합니다.이벤트가 이 모든 구독자에게 게시되고이 구독자에 의해 throw 된 예외 (예외 : )에 관계없이이 메서드는 성공적으로 반환됩니다. 이벤트 클래스에 등록 된 가입자가없고 이벤트가 DeadEvent가 아닌 경우 이 DeadEvent로 랩되고 다시 게시됩니다.

매개 변수 : event - 게시 할 이벤트.

+0

이것은 옳지 않습니다.이 경우 첫 번째 게시물이 모든 이벤트를 반환 할 때입니다. 어느 쪽의 방법이라도 - 이것은 내가 버스가 예상대로 행동 할 수 있는지에 관한 나의 질문에 답하지 않는다. – zmb

5

나는 구아바의 EventBus 이벤트 전달 동작을 요약하려고합니다. 가입자의 게시물 중 하나 이벤트 자체가 @Subscribe -method (작은 순간 이상), 대기열에, 그 후를 전달하는 "새로운"이벤트 E2의에서합니다. 그 이후에 의미 : 결국 @Subscribe- 방법 E1에서 t1에 대한 방법을 반환했습니다.

이러한 종류의 "계단식"이벤트 게시를 광범위한 첫 번째 트리 순회와 비교하십시오.

EventBus의 선택적인 디자인 인 것으로 보입니다.