Abstract: Spring event push mechanism and Aware interface are used to implement the policy pattern and observer pattern, and thread pool is used to asynchronize tasks.

I. Service scenario Description

Suppose we want to develop the class II account opening function of the bank, and the first method of opening account needs to perform the following steps:

  1. Upload basic information
  2. OCR test
  3. Living to identify
  4. Binding bank card

The second method of opening an account only requires:

  1. Upload basic information
  2. OCR test

When submitting the application, it shall be supplemented:

  1. Living to identify
  2. Binding bank card

In both methods, each step must be reported to the monitoring system asynchronously.

Second, the implementation of strategy mode

Let’s first implement the policy mode of two registration modes of routing:

  • Define the registration interface first
public interface OpenAccountHandler {

    void execute();
    
}
Copy the code
  • Implement two kinds of account opening classes

Complete account opening process:

@Component("complete") public class OpenAcctComplete implements OpenAccountHandler{ @Override public void execute() { // Todo follow-up observer pattern implementation}}Copy the code

Brief account opening process:

@Component("partly") public class OpenAcctPartly implements OpenAccountHandler { @Override public void execute() { // Todo follow-up observer pattern implementation}}Copy the code
  • Implement a user-defined route

Here we define an enumeration of opening types:

@getter public enum OpenAcctMethodEnum {this command is used PARTLY(" this command "); Supplement other procedures when applying for payment "); private String type; private String desc; OpenAcctMethodEnum(String type, String desc){ this.type = type; this.desc = desc; } /** * * @param type * @return */ public static OpenAcctMethodEnum getEnumByType(String type){ return Arrays.stream(OpenAcctMethodEnum.values()) .filter(eachEnum -> eachEnum.getType().equals(type)) .findFirst().get(); }}Copy the code

Next, implement the core logic of the route:

@service public class OpenAcctService implements ApplicationContextAware {/** * List */ /* @autowired private Map<String, OpenAccountHandler> openAccountHandlerMap; */ * @resource Private ApplicationContext ApplicationContext; */ private Map<OpenAcctMethodEnum, OpenAccountHandler> openAccountHandlerMap; /** ** @param type Select an account mode */ public void openAccount(String type){ openAccountHandlerMap.get(OpenAcctMethodEnum.getEnumByType(type)).execute(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { final Map<String, OpenAccountHandler> handlerMap = applicationContext.getBeansOfType(OpenAccountHandler.class); openAccountHandlerMap = new HashMap<>(handlerMap.size()); handlerMap.forEach((type, handler) -> openAccountHandlerMap.put(OpenAcctMethodEnum.getEnumByType(type), handler)); }}Copy the code

Here we use ApplicationContextAware’s setApplicationContext(…) Method to initialize the route. We can also do this (comments in the code) :

  1. Direct injectionApplicationContext, and parse the bean.
  2. Spring injectionList, you can inject the registration implementation class directly into the usage class.
  3. Spring injectionMap, similar to thelist.keyIs the name of the bean, or if not customChange the first letter of the class name to lowercase.

Realization of observer mode

After the implementation of the outer policy is complete, the next step is to enter the processing of the owner logic.

  • First of all, we define each event and the corresponding processing method:
@getter Public Class UploadBasicInfoEvent extends ApplicationEvent { Private String Message is also a message reported to the monitoring system. public UploadBasicInfoEvent(Object source) { super(source); } public UploadBasicInfoEvent(Object source, String message) { super(source); this.message = message; }}Copy the code
@Component public class UploadBasicInfoListen implements ApplicationListener<UploadBasicInfoEvent> { @override public void onApplicationEvent(UploadBasicInfoEvent event) { System.out.println(thread.currentThread () + "" + event.getMessage())); }}Copy the code

Similarly for other events, we define each event and its corresponding listener.

  • Publish event

Since events need to be executed asynchronously, let’s see if Spring provides a mechanism for executing events asynchronously. Read the source code and see here:

Here we get the thread pool of the broadcaster. Let’s look at the build of the broadcaster:

As you can see, we can implement asynchronous execution of listener logic by customizing the broadcast. So let’s customize the broadcast first:

/** * @Author winsonWu * @Description: Configuration public class MulticasterConfig {/** * https://juejin.cn/post/7086351322944913438 * @return */ @Bean public ThreadPoolTaskExecutor listenerExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setAllowCoreThreadTimeOut(true); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(5); taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); taskExecutor.setThreadFactory(new CustomizableThreadFactory("event-listener-resolver")); taskExecutor.setAwaitTerminationSeconds(10); return taskExecutor; } / create radio device * * * * @ return * / @ Bean public SimpleApplicationEventMulticaster applicationEventMulticaster(ConfigurableListableBeanFactory beanFactory, @Qualifier("listenerExecutor") ThreadPoolTaskExecutor taskExecutor) { SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(beanFactory); multicaster.setTaskExecutor(taskExecutor); return multicaster; }}Copy the code

Radio apparatus is defined, we can publish event, first of all, in front of the Handler to introduce we define ApplicationEventPublisher, here we provide a brief account opening process code:

/** * @author winsonWu * @description: 2022.04.14 17:08 **/ @Component("partly") public class OpenAcctimplements OpenAccountHandler {@Resource private ApplicationEventPublisher applicationEventPublisher; UploadBasicInfoMsg = uploadBasicInfo(); @override public void execute() {uploadBasicInfoMsg = uploadBasicInfo(); . / / results reported to the monitoring system of applicationEventPublisher publishEvent (new UploadBasicInfoEvent (this, uploadBasicInfoMsg)); // OCR checks final String OCRCheckMsg = OCRCheck(); . / / results reported to the monitoring system of applicationEventPublisher publishEvent (new UploadBasicInfoEvent (this, OCRCheckMsg)); //aliveCheck(); //bindBankCard(); } private String OCRCheck() {OCR system.out.println (thread.currentThread () + "doing OCR"); return "OCRCheck"; } private String uploadBasicInfo() { System.out.println(thread.currentThread () + "doing uploadBasicInfo"); return "uploadBasicInfo"; }}Copy the code

To invoke our defined service:

@SpringBootApplication public class FoundationApplication implements InitializingBean { @Autowired private OpenAcctService openAcctService; public static void main(String[] args) { SpringApplication.run(FoundationApplication.class, args); } @Override public void afterPropertiesSet() throws Exception { openAcctService.openAccount(OpenAcctMethodEnum.PARTLY.getType()); }}Copy the code

Execution Result:

As expected.

Four, gleaning

  • As above, we passSpring event push mechanismwithThe thread poolImplements the business functions defined in Part 1. Of course asynchronous execution events are also available via Spring’s built-in@AsyncAnnotations and custom thread pool implementations are not covered here.
  • Spring provides a variety of features and extension points for us developers to customize logic, such asBeanPostProcessor,BeanDefinitionPostProcessor,awareAnd so on.
  • Used in the codeaware,InitializingBeanIn daily development, initialization method is a common form of preprocessing. Other initialization methods include@postConstructor.init-methodThe mixed use of various initialization methods often occurs in projects. In complex or extreme cases, it is easy to cause disasters due to initialization sequence problems, so we record them hereInitialize theandAutomatic destructionThe order in which methods are executed:

  • In this article, we use spring’s own thread poolThreadPoolTaskExecutor, please refer to The Resources for details.

5. Reference materials

  • Production practices — Thread pooling and asynchronous task choreography
  • Write business code elegantly using Spring features
  • Spring’s built-in thread pool, ThreadPoolTaskExecutor