首頁 > Java > java教程 > 主體

guava eventbus實例代碼詳解

PHP中文网
發布: 2017-06-21 09:25:33
原創
1993 人瀏覽過

分析guava eventbus之前,先看一下傳統觀察者模式的寫法:

#Subject介面是抽象主題,相當於被觀察者,它持有一個監聽者observer的列表,attach方法往這個列表裡面註冊監聽者,detach方法註銷監聽者,notify方法用於事件發生時通知到列表中的監聽者

通常在notify的實作方法中會調用監聽者的update方法。

Observer是抽象觀察者,帶一個update方法,update方法被特定主題的notify方法呼叫。

這是一種傳統的針對介面的程式設計方法。與之不同的是eventbus裡面採用“”隱式接口”,一種基於java Annotation的編程方式。

#區別在於:這種“隱式接口”的對應關係是在程式運行時產生的,而基於真正意義介面與實現的是在編譯時就建立的對應關係,相較之下,「隱式介面」則更加靈活

我們分析下隱式介面以及實作是怎麼建立綁定關係的,看程式碼:

 1 ##SubscriberRegistry类的register方法 2 void register(Object listener) { 3     Multimap<Class<?>, Subscriber> listenerMethods = findAllSubscribers(listener); 4  5     for (Map.Entry<Class<?>, Collection<Subscriber>> entry : listenerMethods.asMap().entrySet()) { 6       Class<?> eventType = entry.getKey(); 7       Collection<Subscriber> eventMethodsInListener = entry.getValue(); 8  9       CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);10 11       if (eventSubscribers == null) {12         CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<Subscriber>();13         eventSubscribers = MoreObjects.firstNonNull(14             subscribers.putIfAbsent(eventType, newSet), newSet);15       }16 17       eventSubscribers.addAll(eventMethodsInListener);18     }19   }
登入後複製

這個方法中有用的就是第3行,其餘的程式碼大致分析一下,就是便利這個Mutimap,將同一類型的事件的監聽者Subsriber加入對應的set當中,如果目前型別事件的Subsriber的set是空,那麼先加一個空的set.

再跟進以上第3行的方法:

##
 1 /** 2    * Returns all subscribers for the given listener grouped by the type of event they subscribe to. 3    */ 4   private Multimap<Class<?>, Subscriber> findAllSubscribers(Object listener) { 5     Multimap<Class<?>, Subscriber> methodsInListener = HashMultimap.create(); 6     Class<?> clazz = listener.getClass(); 7     for (Method method : getAnnotatedMethods(clazz)) { 8       Class<?>[] parameterTypes = method.getParameterTypes(); 9       Class<?> eventType = parameterTypes[0];10       methodsInListener.put(eventType, Subscriber.create(bus, listener, method));11     }12     return methodsInListener;13   }
登入後複製
這個方法中核心的方法是第7行,取得特定class的帶Subscribe註解的所有方法,其餘程式碼的意思是拿到這些方法後,放到多值map當中,然後回傳。

#跟進以上第7行的方法:

1 private static ImmutableList<Method> getAnnotatedMethods(Class<?> clazz) {2     return subscriberMethodsCache.getUnchecked(clazz);3   }
登入後複製
跟倒這裡後,eclipse沒得跟了,懷疑是內部匿名類別呼叫了某個方法相關聯( eclipse對內部匿名類別的呼叫連結也顯示不全)

我們看看這個

subscriberMethodsCache
登入後複製

1 private static final LoadingCache<Class<?>, ImmutableList<Method>> subscriberMethodsCache =2       CacheBuilder.newBuilder()3           .weakKeys()4           .build(new CacheLoader<Class<?>, ImmutableList<Method>>() {5             @Override6             public ImmutableList<Method> load(Class<?> concreteClass) throws Exception {7               return getAnnotatedMethodsNotCached(concreteClass);8             }9           });
登入後複製
load方法被呼叫的時候,呼叫了目前類別的getAnnotatedMethodsNOtCached方法,跟進去這個方法:

 1 private static ImmutableList<Method> getAnnotatedMethodsNotCached(Class<?> clazz) { 2     Set<? extends Class<?>> supertypes = TypeToken.of(clazz).getTypes().rawTypes(); 3     Map<MethodIdentifier, Method> identifiers = Maps.newHashMap(); 4     for (Class<?> supertype : supertypes) { 5       for (Method method : supertype.getDeclaredMethods()) { 6         if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) { 7           // TODO(cgdecker): Should check for a generic parameter type and error out 8           Class<?>[] parameterTypes = method.getParameterTypes(); 9           checkArgument(parameterTypes.length == 1,10               "Method %s has @Subscribe annotation but has %s parameters."11                   + "Subscriber methods must have exactly 1 parameter.",12               method, parameterTypes.length);13 14           MethodIdentifier ident = new MethodIdentifier(method);15           if (!identifiers.containsKey(ident)) {16             identifiers.put(ident, method);17           }18         }19       }20     }21     return ImmutableList.copyOf(identifiers.values());22   }
登入後複製
第2行的意思是拿到目前類別自己+目前類別的父類貨介面的所有類,放在一個Set中

第4行遍歷這個Set

第5行遍歷每個類別的所有方法

第6行呼叫Method的isAnnotationPresent方法判斷目標方法帶有@Subscribe註解,並且這個方法不能是「複合方法」

第16行把複合條件的方法放到map去,並在21行回傳!

以上是guava eventbus實例代碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板