Spring事件(Event)

参考文章:https://www.baeldung.com/spring-events

在spring框架中Events是容易被忽略的功能,事件发布是由ApplicationContext(bean的容器)提供的。下面的简单的提供一些示例代码说明一下相关功能

同步事件处理

下面的示例中说明了注入ApplicationEventPublisher的两种方式,监听事件的两种方式。以及对同一类型的事件监听多次的优先级处理,默认是同步进行处理的,我们可以通过打印日志来验证。

package annotation;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

/**
 * @author chengliangpu
 * @date 2021/10/13
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
        loader = AnnotationConfigContextLoader.class,
        classes = {SpringEvent.CustomSpringEventPublisher.class, SpringEvent.CustomSpringEventListener.class})
public class SpringEvent {
    @Autowired
    private CustomSpringEventPublisher eventPublisher;

    @Test
    public void publish() {
        this.eventPublisher.publishCustomEvent("hello world");
    }

    /**
     * 通过实现ApplicationEventPublisherAware,注入ApplicationEventPublisher
     */
//    @Component
//    public static class CustomSpringEventPublisher implements ApplicationEventPublisherAware {
//        private ApplicationEventPublisher applicationEventPublisher;
//
//        public void publishCustomEvent(final String message) {
//            System.out.println("Publishing custom event. ");
//            System.out.println("Publishing Thread:"+Thread.currentThread().toString());
//            CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
//            applicationEventPublisher.publishEvent(customSpringEvent);
//        }
//
//        @Override
//        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
//            this.applicationEventPublisher = applicationEventPublisher;
//        }
//    }

    /**
     * 最简单的方式是通过@Autowired自动注入ApplicationEventPublisher
     */
    @Component
    public static class CustomSpringEventPublisher {
        @Autowired
        private ApplicationEventPublisher applicationEventPublisher;

        public void publishCustomEvent(final String message) {
            System.out.println("Publishing custom event. ");
            System.out.println("Publishing Thread:" + Thread.currentThread().toString());
            CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
            applicationEventPublisher.publishEvent(customSpringEvent);
        }
    }


    /**
     * 通过实现ApplicationListener注册event监听器
     */
//    @Component
//    public static class CustomSpringEventListener implements ApplicationListener {
//
//        @Override
//        public void onApplicationEvent(CustomSpringEvent event) {
//            System.out.println("Received spring custom event - " + event.getMsg());
//            System.out.println("Received Thread:" + Thread.currentThread().toString());
//        }
//    }

    /**
     * 通过@EventListener注册event监听器
     */
    @Component
    public static class CustomSpringEventListener {

        @EventListener
        @Order(value = Ordered.LOWEST_PRECEDENCE)
        public void onApplicationEvent(CustomSpringEvent event) {
            System.out.println("Received spring custom event - " + event.getMsg());
            System.out.println("Received Thread:" + Thread.currentThread().toString());
        }

        @EventListener
        @Order(value = Ordered.HIGHEST_PRECEDENCE)
        public void onApplicationEvent1(CustomSpringEvent event) {
            System.out.println("Received1 spring custom event - " + event.getMsg());
            System.out.println("Received1 Thread:" + Thread.currentThread().toString());
        }
    }

    public static class CustomSpringEvent extends ApplicationEvent {
        private String msg;

        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public CustomSpringEvent(Object source, String msg) {
            super(source);
            this.msg = msg;
        }

        public String getMsg() {
            return this.msg;
        }
    }
}

我们可以观察监听到的事件是同步的,他们的线程信息是一致的


image.png

异步事件处理

事件的异步处理大体和上面是一样的,只是需要配置一下ApplicationEventMulticaster
完整的示例代码如下

package annotation;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

/**
 * @author chengliangpu
 * @date 2021/10/13
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
        loader = AnnotationConfigContextLoader.class,
        classes = {SpringEventAync.AsynchronousSpringEventsConfig.class, SpringEventAync.CustomSpringEventPublisher.class, SpringEventAync.CustomSpringEventListener.class})
public class SpringEventAync {
    @Autowired
    private CustomSpringEventPublisher eventPublisher;

    @Test
    public void publish() {
        this.eventPublisher.publishCustomEvent("hello world");
    }

    /**
     * 配置event的异步处理,可以观察打印的线程信息查看是否是异步处理
     */
    @Configuration
    public static class AsynchronousSpringEventsConfig {
        @Bean(name = "applicationEventMulticaster")
        public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
            SimpleApplicationEventMulticaster eventMulticaster =
                    new SimpleApplicationEventMulticaster();

            eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
            return eventMulticaster;
        }
    }

    /**
     * 通过实现ApplicationEventPublisherAware,注入ApplicationEventPublisher
     */
//    @Component
//    public static class CustomSpringEventPublisher implements ApplicationEventPublisherAware {
//        private ApplicationEventPublisher applicationEventPublisher;
//
//        public void publishCustomEvent(final String message) {
//            System.out.println("Publishing custom event. ");
//            System.out.println("Publishing Thread:"+Thread.currentThread().toString());
//            CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
//            applicationEventPublisher.publishEvent(customSpringEvent);
//        }
//
//        @Override
//        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
//            this.applicationEventPublisher = applicationEventPublisher;
//        }
//    }

    /**
     * 最简单的方式是通过@Autowired自动注入ApplicationEventPublisher
     */
    @Component
    public static class CustomSpringEventPublisher {
        @Autowired
        private ApplicationEventPublisher applicationEventPublisher;

        public void publishCustomEvent(final String message) {
            System.out.println("Publishing custom event. ");
            System.out.println("Publishing Thread:" + Thread.currentThread().toString());
            CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
            applicationEventPublisher.publishEvent(customSpringEvent);
        }
    }


    /**
     * 通过实现ApplicationListener注册event监听器
     */
//    @Component
//    public static class CustomSpringEventListener implements ApplicationListener {
//
//        @Override
//        public void onApplicationEvent(CustomSpringEvent event) {
//            System.out.println("Received spring custom event - " + event.getMsg());
//            System.out.println("Received Thread:" + Thread.currentThread().toString());
//        }
//    }

    /**
     * 通过@EventListener注册event监听器
     */
    @Component
    public static class CustomSpringEventListener {

        @EventListener
        @Order(value = Ordered.LOWEST_PRECEDENCE)
        public void onApplicationEvent(CustomSpringEvent event) {
            System.out.println("Received spring custom event - " + event.getMsg());
            System.out.println("Received Thread:" + Thread.currentThread().toString());
        }

        @EventListener
        @Order(value = Ordered.HIGHEST_PRECEDENCE)
        public void onApplicationEvent1(CustomSpringEvent event) {
            System.out.println("Received1 spring custom event - " + event.getMsg());
            System.out.println("Received1 Thread:" + Thread.currentThread().toString());
        }
    }

    public static class CustomSpringEvent extends ApplicationEvent {
        private String msg;

        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public CustomSpringEvent(Object source, String msg) {
            super(source);
            this.msg = msg;
        }

        public String getMsg() {
            return this.msg;
        }
    }
}

验证一下输出的日志线程信息,发现监听所使用的线程和发送的确不一样。


image.png

结合泛型和SpEl定义通用事件

@Data
@AllArgsConstructor
public class LogEvent {
    private T source;
    private LogType type;
}

@Slf4j
public class UsualLogListener {
    public UsualLogListener(){

    }

    @Async
    @Order
    @EventListener(classes = LogEvent.class, condition = "#event.type == T(com.springboot.cloud.common.web.entity.enums.LogType).USUAL_LOG")
    public void saveApiLog(LogEvent event) {
        LogUsual logUsual = event.getSource();
        // 测试异步监听,要开启异步参数,在入口需要加上@EnableAsync注解
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info(logUsual.toString());
        // todo:把日志归档到es
    }
}

你可能感兴趣的:(Spring事件(Event))