對於一個對象,若是它能產生或處理某一類型的事件,則須要將其記錄起來,Otto經過HandlerFinder工具類識別這種對象。java
首先看HandlerFinder接口:ide
interface HandlerFinder { Map<Class<?>, EventProducer> findAllProducers(Object listener); Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener); HandlerFinder ANNOTATED = new HandlerFinder() { @Override public Map<Class<?>, EventProducer> findAllProducers(Object listener) { return AnnotatedHandlerFinder.findAllProducers(listener); } @Override public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) { return AnnotatedHandlerFinder.findAllSubscribers(listener); } }; }
這個接口定義了兩個方法來查找給定對象的事件產生方法與監聽方法。對於找到的事件產生對象保存在一個map裏, map的key是事件的類型, value是一個包裝對象EventProducer, 從這裏能夠看出,對於一種事件類型,一個對象最多容許有一個事件產生方法; 對於事件監聽, 一個對象則能夠有多個方法對同一類型事件進行監聽。工具
上述HandlerFinder接口在功能上實際是由AnnotatedHandlerFinder實現的(雖然沒顯示implement);spa
PRODUCER_CACHE 的類型是這樣的 Map<ProducerClass, Map<事件類型, 方法> > , code
SUBSCRIBER_CACHE的類型: Map< SubscriberClass, Map< 事件類型,Set<方法> > >. 對象
由於一個類對某一類型事件只能有一個產生方法, 可是,一個類對某一類型事件能夠有多個監聽方法。接口
loadAnnotatedMethods(Class<?> )掃描一個類,將其帶有標註的方法及對應的事件類型放入相應的cache。事件
注意區分listener 與listenerClass, 前者是一個普通的對象, 後者是listener的 類型(Class)。get
final class AnnotatedHandlerFinder { private static final Map<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE = new HashMap<Class<?>, Map<Class<?>, Method>>(); private static final Map<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE = new HashMap<Class<?>, Map<Class<?>, Set<Method>>>(); static Map<Class<?>, EventProducer> findAllProducers(Object listener) { final Class<?> listenerClass = listener.getClass(); Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>(); if (!PRODUCERS_CACHE.containsKey(listenerClass)) { loadAnnotatedMethods(listenerClass); } Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass); if (!methods.isEmpty()) { for (Map.Entry<Class<?>, Method> e : methods.entrySet()) { EventProducer producer = new EventProducer(listener, e.getValue()); handlersInMethod.put(e.getKey(), producer); } } return handlersInMethod; } /** This implementation finds all methods marked with a {@link Subscribe} annotation. */ static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) { Class<?> listenerClass = listener.getClass(); Map<Class<?>, Set<EventHandler>> handlersInMethod = new HashMap<Class<?>, Set<EventHandler>>(); if (!SUBSCRIBERS_CACHE.containsKey(listenerClass)) { loadAnnotatedMethods(listenerClass); } Map<Class<?>, Set<Method>> methods = SUBSCRIBERS_CACHE.get(listenerClass); if (!methods.isEmpty()) { for (Map.Entry<Class<?>, Set<Method>> e : methods.entrySet()) { Set<EventHandler> handlers = new HashSet<EventHandler>(); for (Method m : e.getValue()) { handlers.add(new EventHandler(listener, m)); } handlersInMethod.put(e.getKey(), handlers); } } return handlersInMethod; }