Bevor wir den Guava-Eventbus analysieren, schauen wir uns an, wie das traditionelle Beobachtermuster geschrieben ist:
Die Subjektschnittstelle ist ein abstraktes Thema, das dem Beobachter entspricht und gilt ein Listener Die Liste der Beobachter, die Attach-Methode registriert den Listener in dieser Liste, die Detach-Methode löscht den Listener und die Notify-Methode wird verwendet, um die Listener in der Liste zu benachrichtigen, wenn ein Ereignis auftritt
wird normalerweise aufgerufen in der Notify-Implementierungsmethode Die Update-Methode des Listeners.
Observer ist ein abstrakter Beobachter mit einer Update-Methode. Die Update-Methode wird von der Notify-Methode des spezifischen Themas aufgerufen.
Dies ist eine traditionelle Programmiermethode für Schnittstellen. Der Unterschied besteht darin, dass Eventbus eine „implizite Schnittstelle“ verwendet, eine Programmiermethode, die auf Java Annotation basiert. Der Unterschied besteht darin, dass die Entsprechung dieser „impliziten Schnittstelle“ generiert wird, wenn das Programm ausgeführt wird, und auf der Grundlage der wahren Die Bedeutung der entsprechenden Beziehung zwischen der Schnittstelle und der Implementierung wird zur Kompilierungszeit hergestellt. Im Gegensatz dazu ist die „implizite Schnittstelle“ flexibler.
Lassen Sie uns analysieren, wie die implizite Schnittstelle und die Implementierung die Bindung herstellen. Um die Beziehung zu bestimmen, Schauen Sie sich den Code an:
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 }
Folgen Sie der Methode in Zeile 3 oben:
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 }
Folgen Sie der Methode in Zeile 7 oben:
1 private static ImmutableList<Method> getAnnotatedMethods(Class<?> clazz) {2 return subscriberMethodsCache.getUnchecked(clazz);3 }
🎜>
Die Lademethode lautet: Beim Aufruf wird die getAnnotatedMethodsNOtCached-Methode der aktuellen Klasse aufgerufen, gefolgt von dieser Methode: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 });
Die zweite Zeile bedeutet, die aktuelle Klasse selbst + die übergeordnete Klasse der aktuellen Klasse abzurufen. Alle Klassen der Schnittstelle werden in einem Set platziert.
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 }
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Guava-Eventbus-Beispielcodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!