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