Use Spring SmartApplicationListener to achieve business decoupling

One, SmartApplicationListener introduction

Spring ApplicationEvent and the corresponding Listener provide an implementation of event monitoring, publish and subscribe. The internal implementation is the observer mode, which can decouple the business between business systems and provide system scalability, reusability, and maintainability.

ApplicationEvent & Listener provided by Spring can be implemented in 3 ways:

  • @EventListener annotation method;
  • Implement the ApplicationListener interface;
  • Implement SmartApplicationListener interface;

This article will introduce how to use SmartApplicationListener.
The SmartApplicationListener interface inherits the ApplicationListener and Ordered interfaces, and implements the functions of event monitoring and sorting.

Insert picture description here
SmartApplicationListener provides two methods:

/**
 *  指定支持哪些类型的事件
 */
boolean supportsEventType(Class<? extends ApplicationEvent> var1);

/**
 *  指定支持发生事件所在的类型
 */
boolean supportsSourceType(Class<?> var1);

Two, SmartApplicationListener code implementation

SmartApplicationListener is an advanced listener, a subclass of ApplicationListener, which can realize orderly monitoring.

The code for this article: https://github.com/nomico271/inspire-demo/tree/master/Ch2_SmartApplicationListener

1. SmartApplicationListener usage example

Assuming that the order creation message needs to be sent to the Kafka cluster for further processing after the order is created, the previous pseudo code may be:

public void createOrder(long spuId) {
    
    
        
        // 创建订单
        long orderId = processCreateOrder(spuId);
        
        // 订单创建成功
        if (orderId > 0) {
    
    
            
            // 发送kafka消息
            sendKafkaMsg(orderId);
        }
        
    }

All processes are coupled together (of course, this article is just an example, some steps must be coupled together).

So how to use SmartApplicationListener to decouple these steps?

(1) First define the event source object, which contains the basic information that needs to be sent.

public class OrderDTO {
    
    private long orderId;
    private String spuId;
    private int orderStatus;
    private Date createTime;
    private Date updateTime;
}

(2) Define what happened:

@Getter
public class OrderStatusMsgEvent extends ApplicationEvent {
    
    
    
    private OrderDTO orderDTO;

    /**
     * 重写构造函数
     *
     * @param source   发生事件的对象
     * @param orderDTO 注册用户对象
     */
    public OrderStatusMsgEvent(Object source, OrderDTO orderDTO) {
    
    
        super(source);
        this.orderDTO = orderDTO;
    }
}

(3) Event release

// 抽象事件发布
public interface EventPublishService<T> {
    
    

    void publishEvent(T event);
}

// Spring 实现的事件发布组件
@Component("springEventPublishService")
public class SpringEventPublishService implements EventPublishService<ApplicationEvent>, ApplicationContextAware {
    
    

    private ApplicationContext applicationContext;
    
    @Override
    public void publishEvent(ApplicationEvent event) {
    
    
        applicationContext.publishEvent(event);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }
}

(4) Event monitoring: When an event occurs, the change notification of the event is monitored for further processing

@Component
public class OrderEventListener implements SmartApplicationListener {
    
    

    /**
     * 支持的事件类型
     *
     * @param eventType
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    
    
        return eventType == OrderStatusMsgEvent.class;
    }

    /**
     * 事件发生的目标类
     *
     * @param sourceType 事件发生的目标类类型
     * @return
     */
    @Override
    public boolean supportsSourceType(@Nullable Class<?> sourceType) {
    
    
        return true;
    }

    @Override
    public int getOrder() {
    
    
        return 0;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
    
    
        // 获取注册用户信息
        OrderStatusMsgEvent orderStatusMsgEvent = (OrderStatusMsgEvent) applicationEvent;
        OrderDTO orderInfo = orderStatusMsgEvent.getOrderDTO();

        // 模拟kafka发送
        // kafkaProducer.sendMsg(orderInfo);
        System.out.println("======kafka发送成功====");

    }
}

(5) Transformation: How to use Spring event publishing mechanism to achieve business decoupling

In the original pseudo code, the above method is used for transformation, the code is as follows:

@Autowired
    @Qualifier("springEventPublishService")
    private EventPublishService publishService;

    public void createOrder(long spuId) {
    
    

        // 创建订单
        long orderId = processCreateOrder(spuId);

        // 订单创建成功
        if (orderId > 0) {
    
    
            // 利用事件发布机制实现创建订单与发送Kafka消息业务的解耦
            OrderDTO orderDTO = buildOrderInfo(orderId);
            publishService.publishEvent(new OrderStatusMsgEvent(this, orderDTO));
        }

    }

The event-driven model implemented by Spring SmartApplicationListener above enables Kafka message sending to be decoupled from the main order process business. Of course, the above is just an example, and it does not reflect the simplicity of applying Spring's event publishing mechanism. This demo is just to introduce the use of Spring SmartApplicationListener. In actual applications, there may be scenarios that are more suitable for business decoupling using this method. For example, when the order status changes, you can use the method introduced in this article to send a message.

2. SmartApplicationListener supports asynchronous usage examples

The Spring event-driven model implemented by SmartApplicationListener can be used in conjunction with the @Asyncannotations provided by Spring to implement asynchronous calls. @AsyncThe implementation is to use the configured thread pool task ThreadPoolTaskExecutor to execute the method where the annotation is located.

(1) Spring configuration method (parameter self-configuration):

  <!-- 开启@AspectJ AOP代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!-- 任务执行器 -->
    <task:executor id="asyncExecutor" pool-size="10" queue-capacity="1024"/>
    <!--开启注解调度支持 @Async @Scheduled-->
    <task:annotation-driven executor="asyncExecutor" proxy-target-class="true"/>

(2) SpringBoot configuration method

@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer {
    
    

    /**
     * 获取异步线程池执行对象
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
    
    
        //使用Spring内置线程池任务对象
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    
    
        return null;
    }
}

When using, just add a @Asynccomment:

@Component
public class OrderEventListener implements SmartApplicationListener {
    
    

    /**
     * 支持的事件类型
     *
     * @param eventType
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    
    
        return eventType == OrderStatusMsgEvent.class;
    }

    /**
     * 事件发生的目标类
     *
     * @param sourceType 事件发生的目标类类型
     * @return
     */
    @Override
    public boolean supportsSourceType(@Nullable Class<?> sourceType) {
    
    
        return true;
    }

    @Override
    public int getOrder() {
    
    
        return 0;
    }

    @Override
    @Async
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
    
    
        // 获取注册用户信息
        OrderStatusMsgEvent orderStatusMsgEvent = (OrderStatusMsgEvent) applicationEvent;
        OrderDTO orderInfo = orderStatusMsgEvent.getOrderDTO();

        // 模拟kafka发送
        // kafkaProducer.sendMsg(orderInfo);
        System.out.println("======kafka发送成功====");

    }
}

Code: https://github.com/nomico271/inspire-demo/tree/master/Ch2_SmartApplicationListener
Reference: https://segmentfault.com/a/1190000011433514

Guess you like

Origin blog.csdn.net/noaman_wgs/article/details/102811177