第四十八讲-事件监听器

第四十八讲-事件监听器

Spring当中有一个非常好的机制,就是事件。事件可以实现组件之间的解耦。本讲我们来看一下事件监听器的使用

1. 事件监听器实现1-实现ApplicationListener接口

如下面的代码:

// 事件解耦例子
@Configuration
public class A48_1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_1.class);
        context.getBean(MyService.class).doBusiness();
        context.close();
    }

    // 自定义一个事件,需要继承Spring提供的ApplicationEvent
    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) { // source 事件源; 事件源是类名+方法名
            super(source);
        }
    }

    @Component
    static class MyService {
        private static final Logger log = LoggerFactory.getLogger(MyService.class);

        // 想要发布一个事件,就要准备一个事件发布器
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness() {
            log.debug("主线业务");
            // 主线业务完成后需要做一些支线业务,如发现短信和发送邮箱,下面是问题代码
            // 事件源
            publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
        }
    }

    @Component
    // 发送短信事件监听器
    // 自定义事件监听器(事件消费者)需要实现Spring提供的ApplicationListener接口
    static class SmsApplicationListener implements ApplicationListener<MyEvent> {
        private static final Logger log = LoggerFactory.getLogger(SmsApplicationListener.class);
        @Override
        public void onApplicationEvent(MyEvent event) {
            log.debug("发送短信");
        }
    }

    // 发送邮箱事件监听器    --> 该监听器只会关注自己感兴趣的事件(在泛型中定义)
    @Component
    static class EmailApplicationListener implements ApplicationListener<MyEvent> {
        private static final Logger log = LoggerFactory.getLogger(EmailApplicationListener.class);
        @Override   // 事件发生时执行的方法
        public void onApplicationEvent(MyEvent event) {
            log.debug("发送邮件");
        }
    }
}

2. 通过@EventListener方法

接下来我们再通过@EventListener方法来监听事件,此外我们发现主线业务,发送邮件,发送短信这三件事是同一个线程串行执行的,因此呢,我们改为异步的形式来实现:

@Configuration
public class A48_2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);
        context.getBean(MyService.class).doBusiness();
        context.close();
    }

    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }

    @Component
    static class MyService {
        private static final Logger log = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness() {
            log.debug("主线业务");
            // 主线业务完成后需要做一些支线业务,下面是问题代码
            publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
        }
    }

    @Component
    static class SmsService {
        private static final Logger log = LoggerFactory.getLogger(SmsService.class);
        @EventListener   // 监听事件,对MyService发布的事件感兴趣
        public void listener(MyEvent myEvent) {
            log.debug("发送短信");
        }
    }

    @Component
    static class EmailService {
        private static final Logger log = LoggerFactory.getLogger(EmailService.class);
        @EventListener   // 监听事件,对MyService发布的事件感兴趣
        public void listener(MyEvent myEvent) {
            log.debug("发送邮件");
        }
    }

    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        return executor;
    }

    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(executor);
        return multicaster;
    }
}

3. @EventListener的原理

接下来我们来研究一下@EventListener注解解析的原理,这里呢我们自定义一个注解,用来取代Spring提供的@EventListener注解来演示一遍:

package com.cherry.springa47;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class A48_2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);
        for (String beanName : context.getBeanDefinitionNames()) {
            Object bean = context.getBean(beanName);
            // 获取该类的所有方法
            for (Method method : bean.getClass().getDeclaredMethods()) {
                // 判断哪个类上加上了@SmsService注解
                if (method.isAnnotationPresent(MyListener.class)) {
                    ApplicationListener listener = new ApplicationListener() {
                        @Override
                        public void onApplicationEvent(ApplicationEvent event) {
                            System.out.println(event);
                            // 获取方法的参数类型信息(监听器方法需要的事件类型)
                            Class<?> eventType = method.getParameterTypes()[0];
                            // 判断类型是否匹配 --> 筛选事件类型
                            if (eventType.isAssignableFrom(event.getClass())) {
                                try {
                                    method.invoke(bean, event);    //反射调用
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    };
                    // 让我们自己写的监听器加入到Spring容器中
                    context.addApplicationListener(listener);
                }
            }
        }
        context.getBean(MyService.class).doBusiness();
        context.close();
    }

    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }

    @Component
    static class MyService {
        private static final Logger log = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;

        public void doBusiness() {
            log.debug("主线业务");
            // 主线业务完成后需要做一些支线业务,下面是问题代码
            publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
        }
    }

    @Component
    static class SmsService {
        private static final Logger log = LoggerFactory.getLogger(SmsService.class);

        @MyListener   // 监听事件,对MyService发布的事件感兴趣
        public void listener(MyEvent myEvent) {
            log.debug("发送短信");
        }
    }

    @Component
    static class EmailService {
        private static final Logger log = LoggerFactory.getLogger(EmailService.class);

        @MyListener   // 监听事件,对MyService发布的事件感兴趣
        public void listener(MyEvent myEvent) {
            log.debug("发送邮件");
        }
    }


    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @interface MyListener {
    }


    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        return executor;
    }

    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(executor);
        return multicaster;
    }
}
posted @ 2024-09-20 09:28  Cherry_Shen  阅读(36)  评论(0)    收藏  举报