EventBus 와 Spring 이벤트 의 차이 에 대한 상세 한 설명 (EventBus 이벤트 메커니즘, Spring 이벤트 메커니즘)

로 컬 비동기 처리, 이벤트 메커니즘 을 사용 하면 코드 를 결합 시 켜 더욱 쉽게 읽 을 수 있 습 니 다.이벤트 메커니즘 실현 모델 은 관찰자 모델 (또는 게시 구독 모델) 로 주로 세 부분 으로 나 뉘 는데 그것 이 바로 게시 자, 감청 자, 사건 이다.
Guava EventBus
Guava EventBus 실현 은 관찰자 모델 로 용법 이 간단 하 며 먼저 코드 를 올 립 니 다.

/**
 * Desc:     
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HelloEvent {
  private String eventName;
}
 
 
@Data
@NoArgsConstructor
public class WorldEvent extends HelloEvent {
 
  private int eventNo;
 
  public WorldEvent(String name, int no) {
    setEventName(name);
    setEventNo(no);
  }
}
 
/**
 * Desc:      ,        。       @Subscribe     。
 */
public class GeventListener {
 
  /**
   *    HelloEvent        (Object)   
   */
  @Subscribe
  public void processEvent(HelloEvent event){
    System.out.println("process hello event, name:" + event.getEventName());
  }
 
  /**
   *    WorldEvent        (HelloEvent   Object)   
   */
  @Subscribe
  public void processWorldEvent(WorldEvent event) {
    System.out.println("process world eventV1, no:" + event.getEventNo() + ", name:" + event.getEventName());
  }
  /**
   *               
   * @param event
   */
  @Subscribe
  public void processWorldEventV2(WorldEvent event) {
    System.out.println("process world eventV2, no:" + event.getEventNo() + ", name:" + event.getEventName());
  }
 
  @Subscribe
  public void processObject(Object object) {
    System.out.println("process common event, class:" + object.getClass().getSimpleName());
  }
}
 
public class GuavaTest {
 
  public static void main(String[] args) {
    EventBus eventBus = new EventBus();
    GeventListener listener = new GeventListener();
    eventBus.register(listener);
 
    eventBus.post(new HelloEvent("hello"));
    eventBus.post(new WorldEvent("world", 23333));
  }
}

결 과 는 다음 과 같다.

//HelloEvent        (HelloEvent  Object     )
process hello event, name:hello
process common event, class:HelloEvent
//WorldEvent        (     ,     )
process world eventV1, no:23333, name:world
process world eventV2, no:23333, name:world
process hello event, name:world
process common event, class:WorldEvent

위 에서 알 수 있 듯 이 Guava EventBus 는 클래스 를 이벤트 로 하고 class 를 key 로 하여 이 벤트 를 등록 하고 관리 하 며 value 는 이벤트 감청 기의 method 입 니 다.이벤트 감청 기 는 특정한 종류의 (부모 클래스) 사건 만 처리 합 니 다.
이벤트 등록 및 발표

//com.google.common.eventbus.EventBus#register
 public void register(Object object) {
 //key Class, value EventSubscriber(Object target, Method method)【  】。    Multimap  HashMultimap,  HashMap>
  Multimap, EventSubscriber> methodsInListener =
    finder.findAllSubscribers(object);
  subscribersByTypeLock.writeLock().lock();
  try {
   subscribersByType.putAll(methodsInListener);
  } finally {
   subscribersByTypeLock.writeLock().unlock();
  }
 }
//com.google.common.eventbus.EventBus#post
 public void post(Object event) {
   //  event       
  Set> dispatchTypes = flattenHierarchy(event.getClass());
  boolean dispatched = false;
  for (Class> eventType : dispatchTypes) {
   subscribersByTypeLock.readLock().lock();
   try {
   //         (     )
    Set wrappers = subscribersByType.get(eventType);
    if (!wrappers.isEmpty()) {
     dispatched = true;
     for (EventSubscriber wrapper : wrappers) {
     //     
      enqueueEvent(event, wrapper);
     }
    }
   } finally {
    subscribersByTypeLock.readLock().unlock();
   }
  }
//             ,   DeadEvent
  if (!dispatched && !(event instanceof DeadEvent)) {
   post(new DeadEvent(this, event));
  }
  dispatchQueuedEvents();
 }

이벤트 격 리
여러 이벤트 버스 는 이 벤트 를 격 리 할 수 있 습 니 다.

public class AnotherListener {
  /**
   *    WorldEvent        (HelloEvent   Object)   
   */
  @Subscribe
  public void processAnotherWorldEvent(WorldEvent event) {
    System.out.println("process another world event, no:" + event.getEventNo() + ", name:" + event.getEventName());
  }
}
public class GuavaTest {
  public static void main(String[] args) {
    EventBus eventBus = new EventBus();
    GeventListener listener = new GeventListener();
    eventBus.register(listener);
    eventBus.post(new HelloEvent("hello"));
    EventBus anotherEventBus = new EventBus();
    AnotherListener anotherListener = new AnotherListener();
    anotherEventBus.register(anotherListener);
    anotherEventBus.post(new WorldEvent("AnotherWorld", 666));
  }
}

결국

//eventBus       

process hello event, name:hello

//anotherEventBus      ,           

process common event, class:HelloEvent

process another world event, no:666, name:AnotherWorld

적용 필드:
  • 유형 에 따라 사건 을 구분한다
  • 구독 이벤트 클 러 스 터
  • 사용자 정의 이 벤트 를 지원 하고 이벤트 에 따라 배포 기
  • 를 직접 쓸 수 있 습 니 다.
  • 사건 격 리
  • spring event
    spring 새 이벤트 메커니즘 도 간단 합 니 다. 코드 를 보 세 요.
    
    /**
     *    ApplicationEvent    
     */
    @Data
    public class HelloEvent extends ApplicationEvent {
      private String eventName;
      public HelloEvent(String eventName) {
        super(eventName);
        setEventName(eventName);
      }
    }
    /**
     *      
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class CustomerEvent {
      private String name;
      private Boolean isCustomer;
    }
    /**
     *     ,spring             
     */
    @Component("springListener")
    public class SpringListener {
      /**
       *     ApplicationEvent            
       */
      @EventListener
      public void processApplicationEvent(ApplicationEvent event) {
        System.out.println("process common event, class:" + event.getClass().getSimpleName());
      }
      /**
       *    HelloEvent     
       */
      @EventListener
      public void processHelloEvent(HelloEvent event) {
        System.out.println("process helloEvent, name:" + event.getEventName());
      }
      /**
       *    CustomerEvent     ,      condition  , isCustomer=true
       */
      @EventListener(condition = "#event.isCustomer")
      public void processCustomerEvent(CustomerEvent event) {
        System.out.println("process customer CustomerEvent, name:" + event.getName());
      }
      /**
       *    CustomerEvent     ,      condition  , name="miaomiao"
       */
      @EventListener(condition = "#event.getName().equals('miaomiao')")
      public void processMiaoMiaoEvent(CustomerEvent event) {
        System.out.println("process miaomiao's CustomerEvent, name:" + event.getName());
      }
      /**
       *         
       */
      @Async
      @EventListener
      public void processAsyncCustomerEvent(CustomerEvent event) {
        System.out.println("Async process CustomerEvent, name:" + event.getName());
      }
    }
    //   ,    
    @SpringBootApplication
    @ComponentScan(basePackages = {"com.example.manyao.async"})
    public class DemoApplication {
      public static void main(String[] args) throws TException {
        SpringApplication.run(DemoApplication.class, args);
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        String[] names = context.getBeanDefinitionNames();
        for(int i=0; i 
     

    결국
    
    //   spring   event,    ApplicationContextEvent。                 。   ApplicationEvent   ,  , processApplicationEvent  。
    process common event, class:ContextRefreshedEvent
    process common event, class:EmbeddedServletContainerInitializedEvent
    process common event, class:ApplicationReadyEvent
    process common event, class:ContextRefreshedEvent
    //        bean
    springListener
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalRequiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    ++++++++++
    //HelloEvent    ApplicationEvent,  processApplicationEvent  
    process common event, class:HelloEvent
    //   HelloEvent     processHelloEvent   
    process helloEvent, name:helloEvent
    //  ApplicationEvent    ,   PayloadApplicationEvent
    process common event, class:PayloadApplicationEvent
    //isCustomer=true,  processCustomerEvent    
    process customer CustomerEvent, name:customer
    //  CustomerEvent  ,    
    Async process CustomerEvent, name:customer
    process common event, class:PayloadApplicationEvent
    //  processMiaoMiaoEvent  
    process miaomiao's CustomerEvent, name:miaomiao
    Async process CustomerEvent, name:miaomiao
    //spring      
    process common event, class:ContextClosedEvent

    spring 컨 텍스트 이벤트
    상술 한 예 중의
    ContextRefreshedEvent, Embedded ServletContainer Initialized Event, ApplicationReadyEvent, ContextRefreshedEvent, ContextClosed Event 등 사건 은 모두 spring 컨 텍스트 사건 입 니 다.이 사건 들 을 감청 함으로써 스프링 생명주기 에 참여 할 수 있다.이런 무 침입 성교 방식 은 플랫폼 서 비 스 를 할 때 좋 은 방식 이다.
    등록 모니터
    org. springframework. context. event. EventListeneMethodProcessor \ # processBean 은 EventListener 를 설명 하 는 모든 방법 을 컨 텍스트 의 applicationListeners 에 저장 합 니 다.Listener 의 패 키 징 클래스 는 ApplicationListener MethodAdapter (String beanName, Class > targetClass, Method method) 입 니 다.
    org. springframework. context. support. AbstractApplicationContext \ # refresh 에서 initApplicationEventMulticaster 를 호출 하여 이벤트 발표 관리자 applicationEventMulticaster 를 초기 화하 고 registerListeners () 등록 모니터 를 호출 합 니 다.
    게시 이벤트
    spring 은 처음에는 애플 리 케 이 션 이벤트 형식 이벤트 만 지원 하 다가 최적화 되면 사용자 정의 이 벤트 를 지원 합 니 다.이벤트 처 리 를 사용자 정의 합 니 다. 기본 값 은 PayloadApplicationEvent 로 EventBus 의 DeadEvent 에 해당 합 니 다.
    
    //org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
      protected void publishEvent(Object event, ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
          logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }
        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
          applicationEvent = (ApplicationEvent) event;
        }
        else {
        //   ApplicationEvent  ,   PayloadApplicationEvent  
          applicationEvent = new PayloadApplicationEvent(this, event);
          if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
          }
        }
        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
          this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
    //    ,    event    
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }
        //    ,    
        // Publish event via parent context as well...
        if (this.parent != null) {
          if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
          }
          else {
            this.parent.publishEvent(event);
          }
        }
      }

    실행 이벤트
    
      @Override
      public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //          ,          
        for (final ApplicationListener> listener : getApplicationListeners(event, type)) {
        //    ,         
          Executor executor = getTaskExecutor();
          if (executor != null) {
            executor.execute(new Runnable() {
              @Override
              public void run() {
                invokeListener(listener, event);
              }
            });
          }
          else {
          //     
            invokeListener(listener, event);
          }
        }
      }

    스프링 의 사건 메커니즘 은 더욱 복잡 하지만 기능 도 마찬가지 로 강하 다 는 것 을 알 수 있다.
    적용 필드:
  • 유형 에 따라 사건 을 구분한다
  • 구독 이벤트 클 러 스 터
  • 사용자 정의 이벤트 지원
  • condition 에 따라 같은 유형의 사건 을 걸 러 냅 니 다
  • EventBus 와 Spring 이벤트 비교
    사용 방식 비교
    항목
    이벤트
    발표 자
    발표 방법
    비동기 여부
    감청 자
    등록 방식
    EventBus
    임 의 대상
    EventBus
    EventBus#post
    예.
    주해 Subscribe 방법
    수 동 등록 EventBus \ # register
    Spring Event
    임 의 대상
    ApplicationEventPublisher
    ApplicationEventPublisher#publishEvent
    동기 화 비동기 지원
    이벤트 Listener 방법 설명
    시스템 등록
    사용 장면 비교
    항목
    이벤트 구분
    이벤트 클 러 스 터 지원 여부
    사용자 정의 이벤트 지원 여부
    필터 지원 여부
    이벤트 격 리 지원 여부
    복잡 도
    EventBus
    Class
    예.
    예.
    아니.
    예.
    간단 하 다.
    Spring Event
    Class
    예.
    예.
    예.
    아니.
    복잡 하 다.
    EventBus 와 Spring Event 에 관 한 더 많은 글 은 아래 의 링크 를 볼 수 있 습 니 다.

    좋은 웹페이지 즐겨찾기