Business background
In the telecommunication business that the author is engaged in, often involves the business that broadband opens an account newly. In the process of broadband account opening at the same time, will involve a lot of other businesses, such as notification work order service (appointment engineer on-site installation), notification management service (application of light cat equipment) and notification message push service (to send short messages to users).
For these businesses, we do a basic implementation
//R1
private WorkOrderService workOrderService;
private ResourceService resourceService;
private PushService pushService;
public void openUser(a) {
User user = new User();//T1
save(user);
// called after successful account opening
workOrderService.openUserHandler(user);//T2
resourceService.openUserHandler(user);//T3
pushService.openUserHandler(user);//T4
}
Copy the code
What problems might arise with the implementation of the above code? If we want to add another business after account opening, for example, user payment needs to be included in the accounting process after account opening, then we need to modify the openUser method, which obviously violates the principle of code design. To address this problem, we introduced an event listener mechanism (or observer pattern, producer consumer pattern, etc.) to decouple the business code.
Event-based implementation
Define events
public interface Event<T> {
void reg(EventHandler eventHandler);
void remove(EventHandler eventHandler);
void notify(T t);
}
Copy the code
Define the receiver of the event
public interface EventHandler<T> {
void handle(T t);
}
Copy the code
Account opening event
public class OpenUserEvent implements Event<User> {
List<EventHandler<User>> eventHandlers = new ArrayList<EventHandler<User>>();
public void reg(EventHandler eventHandler) {
eventHandlers.add(eventHandler);
}
public void remove(EventHandler eventHandler) {
eventHandlers.remove(eventHandler);
}
//R2-notify
public void notify(User user) {
for(EventHandler eventHandler : eventHandlers) { eventHandler.handle(user); }}}Copy the code
Account opening event handler – SMS push service
public class OpenUserEventHandler4SmsPush implements EventHandler<User> {
private SmsPushService pushService = new SmsPushService();
public void handle(User user) { pushService.openUserHandler(user); }}Copy the code
Open account event handler – work order service
public class OpenUserEventHandler4WorkOrder implements EventHandler<User> {
private WorkOrderService workOrderService = new WorkOrderService();
public void handle(User user) { workOrderService.openUserHandler(user); }}Copy the code
Register event handler – Resource service
public class OpenUserEventHandler4Resource implements EventHandler<User> {
private ResourceService resourceService = new ResourceService();
public void handle(User user) { resourceService.openUserHandler(user); }}Copy the code
We have defined several roles above:
-
An Event has the functions of register, unregister, and notify
-
EventHandler (EventHandler), the receiving handler of an event
Start simulating the execution of the main process
// Initialization and registration process
final OpenUserEvent openUserEvent = new OpenUserEvent();
OpenUserEventHandler4SmsPush o1 = new OpenUserEventHandler4SmsPush();
OpenUserEventHandler4Resource o2 = new OpenUserEventHandler4Resource();
OpenUserEventHandler4WorkOrder o3 = new OpenUserEventHandler4WorkOrder();
openUserEvent.reg(o1);
openUserEvent.reg(o2);
openUserEvent.reg(o3);
// Open a thread
new Thread(new Runnable() {
public void run(a) {
User user1 = new User();
System.out.println("Enter account");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
user1.setId("1");
user1.setName("jack");
System.out.println(Account opening completed);
// Notify each event receiver of the account opening event
openUserEvent.notify(user1);
}
}).start();
Copy the code
We have decouple the business based on events. Back to the original question, if you add another business when you open an account, it is easy to build on the existing framework. You don’t need to modify the original business process code, just add an EventHandler.
Solve blocking problems
We optimized the existing code to introduce asynchronous execution.
Compared with the R1 code snippet at the beginning of this article, it is not difficult to calculate the total execution time T
T=T1+T2+T3+T4
Copy the code
In our modified code (see r2-notify), the execution time is actually T, unchanged. Now let’s introduce code into the thread pool to solve the blocking problem.
Define a simple task
The task contains an event handler and processor-dependent objects
class SimpleTask<T> implements Runnable {
private T t;
private EventHandler<T> eventHandler;
public SimpleTask(EventHandler<T> eventHandler, T t) {
this.eventHandler = eventHandler;
this.t = t;
}
public void run(a) { eventHandler.handle(t); }}Copy the code
Thread pools are introduced in the native event
public class OpenUserAsynEvent implements Event<User> {
// Define a thread pool. In practice thread pools can be global or business module level
private Executor executor = Executors.newFixedThreadPool(10);
List<EventHandler<User>> eventHandlers = new ArrayList<EventHandler<User>>();
public void reg(EventHandler eventHandler) {
eventHandlers.add(eventHandler);
}
public void remove(EventHandler eventHandler) {
eventHandlers.remove(eventHandler);
}
//R3-notify
public void notify(User user) {
for (EventHandler eventHandler : eventHandlers) {
executor.execute(newSimpleTask<User>(eventHandler,user)); }}}Copy the code
In contrast to the R3-notify code block, the problem of blocking execution is solved by introducing a thread pool.
At this point, we’ve decoupled the business using event listening. Ok, now we have a new problem, now the system has added to change password (trigger update cache), cancel account (trigger device resource recycling, user data archiving), account recharge (trigger bill cancellation, credit control), based on the existing code structure, then we need to define
ModifyPasswordEvent:
public class ModifyPasswordEvent implements Event<User> {
List<EventHandler<User>> eventHandlers = new ArrayList<EventHandler<User>>();
public void reg(EventHandler eventHandler) {}
public void remove(EventHandler eventHandler) {}
public void notify(User user) {}}Copy the code
ModifyPasswordHandler:
public class ModifyPasswordEventHandler implements EventHandler<User> {
private ModifyPasswordService service = new ModifyPasswordService();
public void handle(User user) {}}Copy the code
CancelEvent(CancelResourceHandler,CancelDocumentHandler)….
Doesn’t it seem like the header is too big, every event is registered and distributed, and there are too many “event-handler” groups that make code maintenance a hassle? At this point, we need to introduce a framework to hide the details of these implementations, complete unified registration and distribution, and let the business focus on the business.
Next time, we’ll introduce Google’s EventBus framework to solve this problem