深入挖掘Spring系列 -- Spring内部的事件机制(下)

简介: 深入挖掘Spring系列 -- Spring内部的事件机制(下)

特殊事件PayloadApplicationEvent

Spring容器中除了提供有ApplicationEvent类型事件之外,还有提供一种叫做

PayloadApplicationEvent的事件类型(也是实现了ApplicationEvent接口)


网络异常,图片无法展示
|


这类事件设计的主要目的在于,发布事件的时候不一定需要定义一个Event对象,可以是直接发送字符串等类型。


使用案例:


package org.idea.spring.framework.event;
import org.springframework.context.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author linhao
 * @Date created in 10:14 下午 2021/5/29
 */
public class PayLoadEventDemo2 implements ApplicationEventPublisherAware {
    public ApplicationEventPublisher applicationEventPublisher;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(PayLoadEventDemo2.class);
        annotationConfigApplicationContext.register(MyPayloadApplicationEventListener.class);
        annotationConfigApplicationContext.refresh();
        PayLoadEventDemo2 payLoadEventDemo = annotationConfigApplicationContext.getBean(PayLoadEventDemo2.class);
        payLoadEventDemo.applicationEventPublisher.publishEvent("hello");
        payLoadEventDemo.applicationEventPublisher.publishEvent(new MyPayloadApplicationEvent<String>(payLoadEventDemo,"payload"));
        annotationConfigApplicationContext.close();
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    /**
     * 可以接收payload事件?
     */
    static class MyPayloadApplicationEventListener implements ApplicationListener<MyPayloadApplicationEvent>{
        @Override
        public void onApplicationEvent(MyPayloadApplicationEvent myPayloadApplicationEvent) {
            System.out.println("[MyPayloadApplicationEventListener] 接收到:%s,"+myPayloadApplicationEvent);
        }
    }
    static class MyPayloadApplicationEvent<String> extends PayloadApplicationEvent<String>  {
        /**
         * Create a new PayloadApplicationEvent.
         *
         * @param source  the object on which the event initially occurred (never {@code null})
         * @param payload the payload object (never {@code null})
         */
        public MyPayloadApplicationEvent(Object source, String payload) {
            super(source, payload);
        }
    }
}
复制代码


这段程序实际上个人感觉是有bug的,因为自己发送的payload事件并没有在监听器中收到消息。


网络异常,图片无法展示
|


后来在Spring内部源代码中的注释说明中跟多是提供给内部框架锁使用的,但是单从SpringFramework 5.2.3版本中的源代码看来,自己并没有看到太多的使用场景。而且关于PayLoad事件在使用过程中感觉源代码中对于事件类型的兼容性也不是太友善,所以不是太推荐使用。


(注意:使用@EventListener的时候,无法监听到PayLoad事件的发送)

事件内部的taskExecutor有何用处


在前边我们提到了可以基于注解的方式来实现异步线程的效果,但是注解的方式更多地是基于方法级别的粒度效果,如果希望实现全局性的事件处理异步化可以重构多播器中的线程池参数:


案例代码:首先需要定义多个Listener


package org.idea.spring.framework.event.multiEvent.listener;
import lombok.SneakyThrows;
import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
 * @Author linhao
 * @Date created in 3:22 下午 2021/5/30
 */
@Component
public class Listener3 implements ApplicationListener<MyAsyncEvent> {
    @SneakyThrows
    @Override
    public void onApplicationEvent(MyAsyncEvent event) {
        System.out.println("3---" + event.getSource() + "thread is " + Thread.currentThread().getName());
        Thread.sleep(1000);
        System.out.println("end 3");
    }
}
package org.idea.spring.framework.event.multiEvent.listener;
import lombok.SneakyThrows;
import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
 * @Author linhao
 * @Date created in 3:22 下午 2021/5/30
 */
@Component
public class Listener2 implements ApplicationListener<MyAsyncEvent> {
    @SneakyThrows
    @Override
    public void onApplicationEvent(MyAsyncEvent event) {
        System.out.println("2---" + event.getSource() + "thread is " + Thread.currentThread().getName());
        Thread.sleep(1000);
        System.out.println("end 2");
    }
}
package org.idea.spring.framework.event.multiEvent.listener;
import lombok.SneakyThrows;
import org.idea.spring.framework.event.multiEvent.events.MyAsyncEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
 * @Author linhao
 * @Date created in 3:22 下午 2021/5/30
 */
@Component
public class Listener1 implements ApplicationListener<MyAsyncEvent> {
    @SneakyThrows
    @Override
    public void onApplicationEvent(MyAsyncEvent event) {
        System.out.println("1---" + event.getSource() + "thread is " + Thread.currentThread().getName());
        Thread.sleep(1000);
        System.out.println("end 1");
    }
}
复制代码


一个自定义的Spring事件


package org.idea.spring.framework.event.multiEvent.events;
import org.springframework.context.ApplicationEvent;
/**
 * @Author linhao
 * @Date created in 3:14 下午 2021/5/30
 */
public class MyAsyncEvent extends ApplicationEvent {
    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public MyAsyncEvent(Object source) {
        super(source);
    }
}
复制代码


一个配置全局性事件异步处理的config,这个配置生效之后,我们就不需要在每个事件接收端都配置@Async注解了


package org.idea.spring.framework.event.multiEvent.events;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.*;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 重写全局性事件异步发送组件
 *
 * @Author linhao
 * @Date created in 3:29 下午 2021/5/30
 */
@Configuration
public class MyEventPublishConfig implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        ApplicationEventMulticaster applicationEventMulticaster = applicationContext.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = (SimpleApplicationEventMulticaster) applicationEventMulticaster;
        ExecutorService taskExecutor = Executors.newFixedThreadPool(10,new CustomizableThreadFactory("pool-idea-"));
        simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor);
        simpleApplicationEventMulticaster.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
            @Override
            public void onApplicationEvent(ContextClosedEvent event) {
                if (!taskExecutor.isShutdown()) {
                    taskExecutor.shutdown();
                    System.out.println("shutdown");
                }
            }
        });
    }
}
复制代码


最后是测试的service


@Service
public class EventTestService {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    public void doSendMsg(){
        System.out.println(" ===== send ===== ");
        applicationEventPublisher.publishEvent(new MyAsyncEvent("this is async"));
    }
}
package org.idea.spring.framework.event.multiEvent;
import org.idea.spring.framework.event.multiEvent.service.EventTestService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.Resource;
/**
 *
 *
 * @Author linhao
 * @Date created in 3:13 下午 2021/5/30
 */
@SpringBootApplication
public class SpringApplicaitonDemo implements CommandLineRunner {
    @Resource
    private EventTestService eventTestService;
    public static void main(String[] args) {
        SpringApplication.run(SpringApplicaitonDemo.class);
    }
    @Override
    public void run(String... args) throws Exception {
        Thread.sleep(1000);
        eventTestService.doSendMsg();
    }
}
复制代码


这样的全局性配置虽然能够减少我们在实际编码过程中异步化操作的繁琐步骤,但是针对的粒度也比较高。所以在实际运用的时候需要结合实际业务场景使用。

目录
相关文章
|
XML Java 数据格式
深度挖掘Spring IoC核心模块源码的宝藏
深度挖掘Spring IoC核心模块源码的宝藏
70 1
|
6月前
|
Java Maven 数据安全/隐私保护
代码优雅升级,提升开发效率:挖掘Spring AOP配置的学习宝藏!
代码优雅升级,提升开发效率:挖掘Spring AOP配置的学习宝藏!
|
设计模式 Java 数据库连接
Spring高手之路7——事件机制与监听器的全面探索
本篇文章为你详细解析了Spring的事件机制,包括了Spring事件模型的四个核心概念:事件源、事件、广播器、监听器。我们通过深入浅出的实例解析了如何自定义事件和监听器,以及如何在实际项目中应用。最后,我们还详细探讨了监听器和Bean的生命周期的关系。无论你是Spring初学者,还是有一定经验的开发者,阅读本文都将帮助你更深入地理解Spring的事件机制和监听器,掌握Spring框架的核心技术。
1082 0
Spring高手之路7——事件机制与监听器的全面探索
|
消息中间件 存储 Java
「Spring和Kafka」Kafka整合Spring 深入挖掘第2部分:Kafka和Spring Cloud Stream
「Spring和Kafka」Kafka整合Spring 深入挖掘第2部分:Kafka和Spring Cloud Stream
|
消息中间件 Java Kafka
「Spring和Kafka」Kafka整合Spring 深入挖掘 -第1部分
「Spring和Kafka」Kafka整合Spring 深入挖掘 -第1部分
|
消息中间件 架构师 Java
「首席架构师看Event Hub」Kafka的Spring 深入挖掘 -第1部分
「首席架构师看Event Hub」Kafka的Spring 深入挖掘 -第1部分
|
XML 存储 Java
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
189 0
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
|
XML 缓存 Java
Spring异步事件机制剖析
Spring异步事件机制剖析
218 0
|
Java Spring
《云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧》电子版地址
云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧
119 0
《云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧》电子版地址
|
开发框架 Java Spring
GitHub榜一大哥!竟是Alibaba内部被疯狂转载的Spring全能指南?
spring相信大家都不会陌生! Spring 是目前主流的 Java Web 开发框架,是 Java 世界上最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。 Spring 由 Rod Johnson 创立,2004 年发布了 Spring 框架的第一版,其目的是用于简化企业级应用程序开发的难度和周期。本教程使用版本为 Spring 5.2。 Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。