52.otto Source Code Analysis

Source: Internet
Author: User
Tags wrappers

Otto Source Code Analysis

Otto's source code is very simple, altogether nine classes.

Project structure
    • Annotatedhandlerfinder (Find and cache all annotation methods)
    • Bus (Otto core business class, including registration, anti-registration, sending events, etc.)
    • deadevent (built-in events, no subscribers, cannot be passed)
    • EventHandler (Package @subscribe method and its class)
    • eventproducer (Package @produce method and its class)
    • Handlerfinder (call Annotatedhandlerfinder method to get the annotation method, encapsulated into EventHandler and Eventproducer collection)
    • Produce (@Produce)
    • Subscribe (@Subscribe)
    • Threadenforcer (for switching threads)
Register implementation Processing @Produce logic
    • 1. Find @Produce method by Annotatedhandlerfinder
    • 2. Then handlerfinder through the recovered package into a Map<Class<?>, EventProducer> set
    • 3. Iterate through the Map<Class<?>, EventProducer> collection and get all the cached EventHandler for that class one by one
    • 4. @Subscribe and @Produce method
    • 5. Call Dispatchproducerresulttohandler Processing: The so-called process of providing @Produce @Subscribe consumption by itself
/** * Find all @Produce methods in the * object by Handlerfinder * Retrieve the package into Eventproducer * and finally return map<class<?>, even tproducer> * *Map<class<?> eventproducer> foundproducers = Handlerfinder.findallproducers (object); for(class<?> Type:foundProducers.keySet ()) {/** * Get Eventproducer one by one * *    FinalEventproducer producer = Foundproducers.get (type);/** * Concurrentmap putifabsent Safe put * prevents concurrency * view cache concurrentmap<class<?> eventproducer> has wood Have * /Eventproducer previousproducer = producersbytype.putifabsent (type, producer);//checking If the previous producer existed    /** * There is a cache first "fried" * *    if(Previousproducer! =NULL) {Throw NewIllegalArgumentException ("Producer method for Type"+ Type +"found on type"+ producer.target.getClass () +", but already registered by type"+ previousProducer.target.getClass () +"."); }/** * Get all cache EventHandler ( @Subscribe Method Encapsulation Class) */set<eventhandler> handlers = Handlersbytype.get (type);if(Handlers! =NULL&&!handlers.isempty ()) { for(EventHandler handler:handlers) {/** * Call @subscribe and @Produce one by one * *Dispatchproducerresulttohandler (handler, producer); }    }}
Handling @SubScribe Logic
    • 1. Find @Subscribe method by Annotatedhandlerfinder
    • 2. Then handlerfinder through the recovered package into a Map<Class<?>, Set<EventHandler>> set
    • 3. Go through Map<Class<?>, Set<EventHandler>> the collection and get the Set<EventHandler> refresh cache
    • 4. Cycle the Map<Class<?>, Set<EventHandler>> collection again to find the cache for the corresponding class Set<EventProducer> .
    • 6. Call Dispatchproducerresulttohandler processing, once again: the so-called process of providing @Produce @Subscribe consumption by itself
/** * Find all @SubScribe methods in the * object by Handlerfinder * Retrieved package into EventHandler * MAP<CLASS<?> set< eventhandler>> * *Map<class<?> set<eventhandler>> Foundhandlersmap = Handlerfinder.findallsubscribers (object);/** * Get EventHandler one by one * * for(class<?> Type:foundHandlersMap.keySet ()) {/** * Get Cache EventHandler Collection * /set<eventhandler> handlers = Handlersbytype.get (type);if(Handlers = =NULL) {//concurrent put if absentSet<eventhandler> handlerscreation =NewCopyonwritearrayset<eventhandler> ();/** * Put a copy of the type corresponding to the Eventhandle set in the cache EventHandler Map * *handlers = Handlersbytype.putifabsent (type, handlerscreation);if(Handlers = =NULL) {handlers = Handlerscreation; }    }Finalset<eventhandler> foundhandlers = Foundhandlersmap.get (type);if(!handlers.addall (Foundhandlers)) {Throw NewIllegalArgumentException ("Object already registered."); }}/** * Traverse all found EventHandler ( @Subscribe method) */ for(Map.entry<class<?>, set<eventhandler>> Entry:foundHandlersMap.entrySet ()) {class<?> type = Entry.getkey ();/** * Take one More time eventproducer cache * If there is @Producer method in the object, the logic of the loop EventHandler is called * Dispat Chproducerresulttohandler method * /Eventproducer producer = Producersbytype.get (type);if(Producer! =NULL&& Producer.isvalid ()) {set<eventhandler> foundhandlers = Entry.getvalue (); for(EventHandler foundhandler:foundhandlers) {if(!producer.isvalid ()) { Break; }if(Foundhandler.isvalid ())            {Dispatchproducerresulttohandler (Foundhandler, producer); }        }    }}
Unregister implementation
    • 1. Find @Produce method by Annotatedhandlerfinder
    • 2. Then handlerfinder through the recovered package into a Map<Class<?>, EventProducer> set
    • 3. Iterate through the Map<Class<?>, EventProducer> collection, get Eventproducer one by one, and go to find out if the Eventproducer cache exists.
    • 4. Cache exists, removed from Eventproducer cache map, call Eventproducer.invalidate () method
/** * Find all @Produce methods in the * object by Handlerfinder * Retrieve the package into Eventproducer * and finally return map<class<?>, even tproducer> * *Map<class<?> eventproducer> Producersinlistener = Handlerfinder.findallproducers (object); for(Map.entry<class<?>, eventproducer> Entry:producersInListener.entrySet ()) {Finalclass<?> key = Entry.getkey ();/** * Get the corresponding Eventproducer * Here is only one to show: * An object only exists a eventproducer * Producer represents the cached object All Eventproducer * value represents all EventHandler found through the Finder */Eventproducer producer = Getproducerforeventtype (key); Eventproducer value = Entry.getvalue ();if(Value = =NULL|| !value.equals (producer)) {Throw NewIllegalArgumentException ("Missing event producer for an annotated method." Is "+ object.getclass () +"Registered?"); }/** * Remove * from Eventproducer cache map and call Eventproducer.invalidate () method * Set the Eventproducer illegal * *Producersbytype.remove (Key). Invalidate ();}
    • 1. Find @Subscribe method by Annotatedhandlerfinder
    • 2. Then handlerfinder through the recovered package into a Map<Class<?>, Set<EventHandler>> set
    • 3. Iterate through the Map<Class<?>, Set<EventHandler>> collection, get the Set<EventHandler> collection, and see if the cache exists.
    • 4. There is a cache, continue to traverse Set<EventHandler> the collection, get EventHandler.
    • 5. If the cache is EventHandler, there is a Finder first check in the EventHandler, marked as illegal.
    • 6. Delete the Set<EventHandler> cache for this collection
Post implementation

First of all, here's a way to do all the parent classes of a class, including yourself, stored as a set set.
Also Otto a tool method .

Getclassesfor

/** * Find a class All parent classes include themselves as a set set * * @param concreteclass concreteclass * @return set<class& lt;? >> * *PrivateSet<class<?>>getclassesfor(class<?> Concreteclass) {List<class<?>> parents =NewLinkedlist<class<?>> (); set<class<?>> classes =NewHashset<class<?>> (); Parents.add (Concreteclass); while(!parents.isempty ()) {class<?> clazz = Parents.remove (0);        Classes.add (Clazz); class<?> parent = Clazz.getsuperclass ();if(Parent! =NULL) {Parents.add (parent); }    }returnClasses;}

Then talk about the implementation of the post -specific process:

    • 1. Use the flattenHierarchy method to deal with the family tree collection of events (self + Parent class collection), return a Set<Class<?>> collection
    • 1.1. flattenHierarchy method First look at whether there is a family tree collection of the event in the flattenhierarchycache cache (self + parent class collection)
    • The cache of the event exists in 1.2.Flattenhierarchycache and returns directly
    • 1.3.Flattenhierarchycache does not exist in the cache of the event, it is called getClassesFor to collect the family tree collection of that class (itself + the collection of parent classes), caching a copy to Flattenhierarchycache , and then return
    • 2. Walk through this Set<Class<?>> collection (Family tree collection), then get the cache collection of the Listener class, then Set<EventHandler> iterate through the Set<EventHandler> collection, enter into the enqueueEvent inside with event + EventHandler wrapped into Eventwithhandler object, and Execute Queue Logic
    • 3. Determine if the event has no subscribers and is not a deadevent event. Match, give a deadevent event
    • 4. Finally will slip dispatchQueuedEvents into the processing event queue
/** * Get the event + the set set of all parent classes of the event */set<class<?>> dispatchtypes = FlattenHierarchy (Event.getclass ());Booleandispatched =false;/** * Iterates over the event + the set set of all parent classes of the event */ for(class<?> eventtype:dispatchtypes) {/** * Get the object all cache EventHandler */set<eventhandler> wrappers = Gethandlersforeventtype (EventType);/** * Start to go through the EventHandler of the cache * and handle the event * Enter enqueueevent logic */    if(Wrappers! =NULL&&!wrappers.isempty ()) {dispatched =true; for(EventHandler wrapper:wrappers) {/** * Event + EventHandler packed into Eventwithhandler * * *Enqueueevent (event, wrapper); }    }}/** * According to the above loop can be known * If an object exists a EventHandler * and the post event is not deadevent * The post is executed once (new Deadevent (this, event)) */< /c3>if(!dispatched &&!) (EventinstanceofDeadevent)) {post (NewDeadevent ( This, event));} Dispatchqueuedevents ();
Annotated source code

Annotated source code

52.otto Source Code Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.