spring 事件监听器的使用及事件异步处理

10 篇文章 0 订阅
4 篇文章 0 订阅

spring 中的事件监听机制是运用观察者模式来实现的,观察者模式的优点有:

1、观察者和被观察者之间低耦合,代码比较好维护

2、被观察者和观察者之间是一对多的关系(当然也可以一对一),当被观察者状态改变的时候,多个观察者能同时进行处理,能实现广播通讯

观察者模式有两种角色:

1、Subject 目标角色:接收外界的状态变化,向观察者发送通知(广播通知)        

2、Observer 观察者角色:观察Subject状态变化,触发具体操作逻辑

所以说subject  和 observer之间是一对多的关系

 现在我们用spring监听机制来实现上述图示:

observer1,observer2,observer3监听subject1的状态变化

observer3,observer4监听subject2的状态变化

可见observer3同时可以监听subject1,subject2的状态变化

Subject1:声明事件1,Object source是通信传输数据的实体
/**
 * @Author yangcai
 * @create 2022/6/24 15:47
 */
public class Subject1 extends ApplicationEvent {

    public Subject1(Object source) {
        super(source);
    }
}
Subject2:声明事件2,Object source是通信传输数据的实体
/**
 * @Author yangcai
 * @create 2022/6/24 15:47
 */
public class Subject2 extends Subject1 {
    public Subject2(Object source) {
        super(source);
    }
}
EventPublisher:事件发布器,给监听器发送通知,触发监听器的执行
@Component
@Slf4j
public class EventPublisher implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher eventPublisher;

    public void publish(ApplicationEvent event)  {
        eventPublisher.publishEvent(event);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.eventPublisher = applicationEventPublisher;
    }

}

@Data
public class SourceEntity {
    private String subjectName;
    private String notifyMsg;
}

 ObserverEventHandler 声明监听器及监听的事件,多个监听器可以监听一个事件

/**
 * @Author yangcai
 * @create 2022/6/24 15:48
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ObserverEventHandler {

    @EventListener(id="observer1",condition = "@listenerPredicate.test(#event)")
    public void handle1(Subject1 event) {
        SourceEntity sourceEntity = (SourceEntity)event.getSource();
        log.info("--observer1---handle1-----"+sourceEntity.getSubjectName());
    }
    @EventListener(id="observer2",condition = "@listenerPredicate.test(#event)")
    public void handle2(Subject1 event) {
        SourceEntity sourceEntity = (SourceEntity)event.getSource();
        log.info("--observer2---handle2-----"+sourceEntity.getSubjectName());
    }
    @EventListener(id="observer3")
    public void handle3(Subject1 event)  {
        SourceEntity sourceEntity = (SourceEntity)event.getSource();
        log.info("--observer3---handle3-----"+sourceEntity.getSubjectName());
    }

    @EventListener(id="observer4")
    public void handle4(Subject2 event)  {
        SourceEntity sourceEntity = (SourceEntity)event.getSource();
        log.info("--observer4---handle4-----"+sourceEntity.getSubjectName());
    }
}

监听器监听事件的条件匹配器,可以根据通信实体中的数据,当事件被发布时,来进行判断当前监听器是否会触发执行

/**
 * @Author yangcai
 * @create 2022/6/28 16:20
 */
@Component
public class ListenerPredicate implements Predicate<ApplicationEvent> {
    @Override
    public boolean test(ApplicationEvent event) {
        SourceEntity sourceEntity = (SourceEntity)event.getSource();
        if(event instanceof  Subject2 && "subject2".equals(sourceEntity.getSubjectName())){
            return false;
        }
        return true;
    }
}

测试subject1: 

@SpringBootApplication
public class Stu1Application {

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ac = SpringApplication.run(Stu1Application.class, args);
        SubjectPublisher eventPublisher = ac.getBean(SubjectPublisher.class);
        SourceEntity sourceEntity = new SourceEntity();
        sourceEntity.setSubjectName("subject1");
        eventPublisher.publish(new Subject1(sourceEntity));
    }
}

 ​​​结果:

 测试subject2: 

@SpringBootApplication
public class Stu1Application {

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ac = SpringApplication.run(Stu1Application.class, args);
        SubjectPublisher eventPublisher = ac.getBean(SubjectPublisher.class);
        SourceEntity sourceEntity = new SourceEntity();
        sourceEntity.setSubjectName("subject2");
        eventPublisher.publish(new Subject2(sourceEntity));
    }
}

  ​​​结果:

 配置监听器异步执行:需要新增两个配置文件

/**
 * @Author yangcai
 * @create 2022/6/24 15:57
 */
@Configuration
public class ApplicationEventAsyncConfig {

    @Resource
    private ThreadPoolTaskExecutor myExecutor;

    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster() { //@1
        //创建一个事件广播器
        SimpleApplicationEventMulticaster result = new SimpleApplicationEventMulticaster();
        //设置异步执行器,来完成异步执行监听事件这样会导致所有的监听器都异步执行
        result.setTaskExecutor(myExecutor);
        return result;
    }
}
@Configuration
public class ThreadPoolConfig {

    @Bean("myExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(8);
        taskExecutor.setMaxPoolSize(20);
        taskExecutor.setQueueCapacity(50);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("eventHandle--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值