guava EventBus 觀察者模式

guava EventBus 觀察者模式

主要有主題和觀察者,主題發生變化時,通知觀察者(用戶只要提供觀察者,並且向主題中註冊即可),其中在操作subscribersByType都開啓鎖了。所以這個EventBus 主要提供線程安全和註解的方式簡化代碼。
1. 向EventBus 註冊觀察者時,找出這個觀察者的帶有@Subscribe 的方法,並且這個方法只有一個參數。
可以@AllowConcurrentEvents來不同步的,沒有的就同步來執行方法
向subscribersByType 註冊這個參數類型和方法 ,即下面的listen的參數類型Long和listen方法
2. 發佈消息
根據發佈的對象類型,從subscribersByType 找出方法,
把這些方法先放到隊列中,然後再一個個執行。

  • 建觀察者,這裏的訂閱方法只要加上@Subscribe即可
  public class LongListener {  
      @Subscribe  
      public void listen(Long integer) {  …} 
   }
  • 註冊觀察者併發布消息
   EventBus eventBus = new EventBus("test");  
   LongListener n = new LongListener();
   eventBus.register(n); 
   eventBus.post(new Long(1)); 
   //根據註解 來找到一些方法,再根據參數類型來確定哪些觀察者
  • 具體看下EventBus
   class EventBus {
      private final ReadWriteLock subscribersByTypeLock = new     ReentrantReadWriteLock();//這個是同步
      private final SetMultimap<Class<?>, EventSubscriber> subscribersByType = HashMultimap.create();//value是個集合,存放觀察者
      private final SubscriberFindingStrategy finder = new AnnotatedSubscriberFinder();// 尋找觀察者的幫助類
      private final **ThreadLocal**<Queue<EventWithSubscriber>> eventsToDispatch =
      new ThreadLocal<Queue<EventWithSubscriber>>();//存放要執行的觀察者,這個是線程安全
      Public EventBus(String str) {
         this.exceptionHandler = new Longging..Exception(str);//報錯信息
      }
      **//向這個主題中註冊觀察者**
      public void register(Object object) {
         Multimap<Class<?>, EventSubscriber> methodsInListener = finder.findAllSubscribers(object);
         subscribersByTypeLock.writeLock().lock();//開啓寫鎖,其他線程不讀不寫
         try {
            subscribersByType.putAll(methodsInListener);
         } finally {
            subscribersByTypeLock.writeLock().unlock();//釋放寫鎖
         }
      } 
      **//註銷觀察者**
      public void unregister(Object object) { 
          Multimap<Class<?>, EventSubscriber> methodsInListener = finder.findAllSubscribers(object);
          //下面代碼就省略了,主要就是開啓寫鎖,從methodsInListener 去掉object,然後關閉寫鎖
          ....
      }
      **//這個就相當於通知觀察者 event 是個類型,根據這個類型找到觀察者**
      public void post(Object event) {
           Set<Class<?>> dispatchTypes = TypeToken.of(event.getClass()).getTypes().rawTypes();//這個類的父類和父接口
          //遍歷dispatchTypes,並且開啓讀鎖,其他線程只讀不寫
           Set<EventSubscriber> wrappers = subscribersByType.get(eventType);//取出這個類的觀察者
           //遍歷wrappers 將wrapper加到執行觀察者隊列中
           eventsToDispatch.get().offer(new EventWithSubscriber(event, wrapper)); 
          //關閉讀鎖

          if (!dispatched && !(event instanceof DeadEvent)) 
              post(new DeadEvent(this, event));

          //執行隊列中的觀察者(遍歷隊列中的,執行觀察者並從隊列中移除)
          try {
              Queue<EventWithSubscriber> events = eventsToDispatch.get();
              eventWithSubscriber.subscriber.handleEvent(eventWithSubscriber.event); 
              //這個就是利用反射調用方法
           } finally {
              eventsToDispatch.remove();//刪除隊列
           }
      }
  }
  • AnnotatedSubscriberFinder 主要根據類型來找出符合條件的方法(觀察者中有@Subscribe的方法的第一個參數類型 – 和這個方法)
 class AnnotatedSubscriberFinder implements SubscriberFindingStrategy { 

     //獲取 觀察者的參數類型和對應的方法(@Subscribe)
     public Multimap<Class<?>, EventSubscriber> findAllSubscribers(Object listener) {
         Multimap<Class<?>, EventSubscriber> methodsInListener = HashMultimap.create();
         //從緩存中獲取符合條件的方法
         for (Method method : subscriberMethodsCache.getUnchecked(listener.getClass())) {
            EventSubscriber subscriber= null;
            //這裏就是同步
            if(method.getAnnotation(AllowConcurrentEvents.class) != null)
              subscriber = new EventSubscriber(listener, method);
            else
              subscriber = new SynchronizedEventSubscriber(listener, method); 

            methodsInListener.put(**method.getParameterTypes()[0]**, subscriber);//是這個方法的第一個參數類型
         }
    }
    return methodsInListener;
  }

  //就是獲取這個類(包括父類,父接口)的帶有@Subscribe並且只有一個參數類型的
  private static ImmutableList<Method> getAnnotatedMethodsInternal(Class<?> clazz) {
    Map<MethodIdentifier, Method> identifiers = Maps.newHashMap();
    for (Class<?> superClazz : TypeToken.of(clazz).getTypes().rawTypes()) {
      for (Method superClazzMethod : superClazz.getMethods()) {
        if (superClazzMethod.isAnnotationPresent(**Subscribe.class**)) {
          Class<?>[] parameterTypes = superClazzMethod.getParameterTypes();
          if (parameterTypes.length != 1) throw new Ex....(...);
          ...//存放到identifiers 
        }
      }
    }
    return ImmutableList.copyOf(identifiers.values());
  }


    //採用沒有引用了就刪除的緩存,主要是存放這個類和方法
    private static final LoadingCache<Class<?>, ImmutableList<Method>> subscriberMethodsCache = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader<Class<?>, ImmutableList<Method>>() {
      public ImmutableList<Method> load(Class<?> concreteClass) throws Exception {
         return getAnnotatedMethodsInternal(concreteClass);
      }
     }); 
 }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章