In the project development process, often some functional surface looks simple, but the actual development results are very complex, careful analysis of the reasons for the discovery of a lot because of the addition of many additional features.
Is it really easy?
For example, we have an e-commerce platform to make changes to the product data function, in fact, is very simple, but the operator in the management platform to modify the product data, and then click Submit, the core function is indeed very simple, but may be asked to modify the product need to increase the operation of the log, There is also the need to automatically update the data in the retrieval system after the modification of the commodity data, the summary of the changes in the commodity data need to be audited by the audit to take effect, but also some people need to send e-mail notification to operators, and so on, so that the product modification function is not so simple, it in addition to complete their mission, There is also a need to invoke other services to complete the activity similar to the following:
Horizontal mainstream, up and down four small boxes are additional functions, complex reasons include the following two points:
- Additional functions result in more function opening and increased workload.
- Additional functions lead to complex program logic, need to access other services in the program, but also to consider data integrity, performance, service dependencies and other issues.
At first, when we developed in the project, we used the simplest strong coupling to call the service directly, for example, after calling the method of data saving, call Logservice log method, call Esservice method to update the retrieval system, Call Mailservice method to send e-mail, this will lead to our productservice strong coupling of these and the commodity preservation logic is not directly related to the service, so that the function of the product preservation seems to be less simple, that is, we mentioned the complexity of the article, there will be similar code:
@Autowired Private searchservice searchservice; @Autowired Private mailservice mailservice; @Autowired Private Productlogservice Productlogservice; // the code snippet to save the item below Itemdao.save (product); Searchservice.update (Product.getid ()); Mailservice.post (Product.getid ()); LogService.log (Product.getid ());
The problem is as follows:
- Strong coupling of services to non-business direct correlation
- There may be performance issues, such as you need to be concerned about whether mail sending affects the main process
- Code readability is poor, too much logic can easily lead to the separation of core functions of the main body
What if we fix it? There is a design pattern that can be solved, that is, the observer pattern, before learning. Net wrote a (cliché: Observer pattern), which refers to the traditional way of implementation and event mechanism, the implementation of the event mechanism is relatively simple, Here we refer to the Eventbus provided in the guava component when solving this problem, which is similar to the implementation of the previous observer pattern, as shown in the following diagram, where there is no complex dependency between functions.
Note: Guava's eventbus is an in-process level, unable to cross the process, after I take the time to clean up the distributed event summary based on Message Queuing.
I'm not going to show you how to use Eventbus, but rather focus on the application of it in our project, and what's bad.
First: To have observers, here we encapsulate different observers based on different business, the following is the class to update the retrieval system data
@Service Public classSearcheventlistener {@Autowired () Productupdatemgr productsearchupdatemgr; Private Final StaticLogger Logger = Loggerfactory.getlogger (Searcheventlistener.class); @Subscribe Public voidListen (String Itemlegacyid) {Try{productsearchupdatemgr.markproductdirty (Itemlegacyid); } Catch(Exception ex) {Logger.error ("Update Search exception:" + ex.getmessage () +ex.getstacktrace ()); } } }
Second: There is a need to register the observer with Eventbus, and we have written a class to do it and do two things:
- Registering the observer into the Eventbus
- Further wrapping the Post method so that the caller is called as a service, so that Productservice relies on eventbus instead of relying on the actual retrieval service, mail service, etc.
@Service Public classEventlistenermanager {Eventbus mmsproducteventbus; Eventbus Mmsitemeventbus; Eventbus Mmssearcheventbus; Eventbus Mmsrebuildallsearcheventbus; Eventbus Mmscommonlogeventbus; @Autowired Itemeventlistener ItemListener; @Autowired Producteventlistener Productlistener; @Autowired Searcheventlistener Searchlistener; @Autowired Rebuildallsearcheventlistener Rebuildallsearchlistener; @Autowired Mmscommonlogeventlistener Commonloglistener; @PostConstructPrivate voidinit () {Mmsproducteventbus=NewEventbus (); Mmsitemeventbus=NewEventbus (); Mmssearcheventbus=NewEventbus (); Mmsrebuildallsearcheventbus=NewEventbus (); Mmscommonlogeventbus=NewEventbus (); Mmsitemeventbus.register (ItemListener); Mmsproducteventbus.register (Productlistener); Mmssearcheventbus.register (Searchlistener); Mmsrebuildallsearcheventbus.register (Rebuildallsearchlistener); Mmscommonlogeventbus.register (Commonloglistener); } Public voidNotifyitemlog (Long itemId) {mmsitemeventbus.post (itemId); } Public voidNotifyproductlog (Long productId) {mmsproducteventbus.post (productId); } Public voidNotifyupdatesearch (String Itemlegacyid) {mmssearcheventbus.post (Itemlegacyid); } Public voidNotifyrebuildallsearch () {Mmsrebuildallsearcheventbus.post (""); } Public voidNotifyaddcommonlog (Mmscommonlogmodel log) {mmscommonlogeventbus.post (log); }}
What are the above implementations and what problems have we encountered when we first learned to use guava eventbugs?
question one: Why does the above code have so many eventbus instead of one? Notice the Post method of Enventbus, we look at its source code: it is based on the type of the parameter to find the method of the observer registration, and we write the Observer class in the method of the parameters are some primitive type, a total of about 10 methods, It is difficult to correctly identify which method to call in a eventbus based on the parameter type.
Public voidPost (Object event) {Set<Class<?>> dispatchtypes =FlattenHierarchy (Event.getclass ()); Booleandispatched =false; for(class<?>eventtype:dispatchtypes) {Subscribersbytypelock.readlock (). Lock (); Try{Set<EventSubscriber> wrappers =Subscribersbytype.get (EventType); if(!Wrappers.isempty ()) {Dispatched=true; for(Eventsubscriber wrapper:wrappers) {enqueueevent (event, wrapper); } } } finally{subscribersbytypelock.readlock (). Unlock (); } } if(!dispatched &&!) (Eventinstanceofdeadevent)) {Post (NewDeadevent ( This, event)); } dispatchqueuedevents (); }
How to solve? you can encapsulate a class for each method's parameters, such as updating the method parameter called Searchchangeevent, send the audit message parameters called Approvalchangeevent, etc. So that we can register all the observers in a eventbus, there will be no problem when the Post method is called, and the result of the simplification is as follows:
@AutowiredEventListenerManager EventManager; Code Snippet Itemdao.save (product) to save the item below, Eventmanager.post (new searchchangeevent (Product.getid)) ; Eventmanager.post (new mailchangeevent (Product.getid)); Eventmanager.post (New Logchangeevent ( Product.getid));
problem Two: performance issues, previously mentioned that the additional function will cause the original simple things are not simple, such as invoking some services may affect the overall performance, then we assume that the use of Enventbus itself is asynchronous, in fact, if it is synchronous with Eventbus, This class is needed to complete asynceventbus to use async.
problem three: strong coupling problem, because we have eventlistenermanager, we do not need to rely on the service that is not directly related in the concrete business, You just have to rely on Eventlistenermanager, a management class that looks unrelated to the task business.
Through the actual project of the application of Eventbus to analyze the problems it can solve and the original application needs to be improved place. It is shown that Eventbus application can simplify program complexity, improve code readability, and reduce development and maintenance costs.
Problems solved by applying eventbus in the project