深入挖掘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核心模块源码的宝藏
73 1
|
15天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
46 8
|
7月前
|
Java Maven 数据安全/隐私保护
代码优雅升级,提升开发效率:挖掘Spring AOP配置的学习宝藏!
代码优雅升级,提升开发效率:挖掘Spring AOP配置的学习宝藏!
|
设计模式 Java 数据库连接
Spring高手之路7——事件机制与监听器的全面探索
本篇文章为你详细解析了Spring的事件机制,包括了Spring事件模型的四个核心概念:事件源、事件、广播器、监听器。我们通过深入浅出的实例解析了如何自定义事件和监听器,以及如何在实际项目中应用。最后,我们还详细探讨了监听器和Bean的生命周期的关系。无论你是Spring初学者,还是有一定经验的开发者,阅读本文都将帮助你更深入地理解Spring的事件机制和监听器,掌握Spring框架的核心技术。
1190 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对象的深入分析和挖掘指南
200 0
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
|
XML 缓存 Java
Spring异步事件机制剖析
Spring异步事件机制剖析
225 0
|
Java Spring
《云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧》电子版地址
云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧
121 0
《云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧》电子版地址
下一篇
DataWorks