dreamzy996

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  12 随笔 :: 0 文章 :: 0 评论 :: 36454 阅读

一、组成部分

spring的事件监听有三个部分组成,事件(ApplicationEvent)、监听器(ApplicationListener)和事件发布操作。

二、具体实现

事件

事件对象就是一个简单的po实体类

1、需要实现接口ApplicationEvent,

2、构造方法需要设置super

3、我们可以另外拓展一些子类来区分不同事件的实体

复制代码
public abstract class BaseEvent<T> extends ApplicationEvent {

    protected T eventData;
    protected String topic;

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source 事件产生处所在类的对象
     * @param eventData 表示在事件传播过程中,需要传输的对象,随意设置数据类型
     * @param topic topic
     */
    public BaseEvent(Object source, T eventData,String topic) {
        super(source);
        this.eventData = eventData;
        this.topic = topic;
    }

    public T getEventData() {
        return eventData;
    }
    public String getTopic(){
        return topic;
    }
}
复制代码

子类举例

复制代码
public class SimpleEvent<T> extends BaseEvent {
    //需要传输的事件主题
    private String topic;
    //用于接受事件的返回值
    private List result;
    public SimpleEvent(Object source) {
        super(source);
    }
    public SimpleEvent(Object source, T eventData) {
        super(source, eventData);
    }
    public SimpleEvent(Object source, T eventData, String topic) {
        super(source,eventData);
        this.topic = topic;
    }
    public void setResult(List<String> result) {
        this.result = result;
    }
    public String getTopic() {
        return topic;
    }
    public List<String> getResult() {
        return result;
    }
}
复制代码

发布者

发布者很简单,需要注意三点

1、注入到spring容器中

2、引入应用上下文让我们的事件发布到流程中

3、调用 publishEvent 时传入事件po对象

复制代码
@Component
public class SimpleEventPublisher<T> {
    @Resource
    ApplicationContext applicationContext;
    public void publish(T msg) {
        applicationContext.publishEvent(new SimpleEvent<>(this, msg));
    }
    public void publish(T msg, String topic) {
        applicationContext.publishEvent(new SimpleEvent<>(this, msg, topic));
    }
    public List<String> publishAndReceive(T msg, String topic) {
        SimpleEvent<T> simpleEvent = new SimpleEvent<>(this, msg, topic);
        applicationContext.publishEvent(simpleEvent);
        return simpleEvent.getResult();
    }
}
复制代码

监听者

两种实现方式

1、@EventListener 注解实现

  @EventListener 所在的监听方法是根据参数列表的EventPo类型来进行监听的,正常来讲对不同的事件po监听需要对应不同的监听方法。

  @EventListener 也有两个参数 classes(事件po类) 和 condition(满足条件走此方法) ,这两个参数默认不用填写

  如果多个监听方法的入参事件po列表一致,就会重复监听同一个事件。

2、类实现

  实现 ApplicationListener<事件PO>  并重写方法就行

复制代码
@Component
public class SimpleEventListener {
    public static final String eventBindTopic ="event#setNeedBindInfo";
    public static final String eventBindBackTopic ="event#setBindBackTopic";
    @Order(0)
    @EventListener
    public void doMsg(SimpleEvent<String> simpleEvent){
        if (simpleEvent.getTopic().equals(eventBindTopic)){
            UserEventDto eventData = (UserEventDto) simpleEvent.getEventData();
            log.info("普通监听器-》接受到事件[{}],数据体【{}】",simpleEvent.getTopic(),eventData);
        }else if (simpleEvent.getTopic().equals("event#setBindBackTopic")){
            // 由于传入的事件与前面发布的事件内存地址指向的是同一个,这里可以设置值用于返回
            simpleEvent.setResult(Collections.singletonList("这里是返回参数pong"));
            log.info("有返回值监听器-》 topic【{}】,全数据体【{}】",simpleEvent.getTopic(), simpleEvent);
        }else {
            log.info("无匹配监听器 topic【{}】,数据体【{}】", simpleEvent.getTopic(),simpleEvent.getEventData());
        }
    }
}
复制代码

三、原理探寻

一、解析@EventListener前的准备工作

1.1 EventListenerFactory和EventListenerMethodProcessor的注入

  EventListenerFactory 是把 @EventListener 标注的方法变成 ApplicationListener 的关键,其是在容器最初期(refresh方法发生前)就放到容器中去

  EventListenerMethodProcessor 是 @EventListener 的解析类,他是一个 SmartInitializingSingleton 和 BeanFactoryPostProcessor

  ApplicationListener 是把 @EventListener 包装了一层

  初始化的时候先判断,没有就注入 EventListenerMethodProcessor 和  DefaultEventListenerFactory 到容器中

源码如下

复制代码
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, Object source) {
        //获取对象
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        
        //org.springframework.context.event.internalEventListenerProcessor
        //@EventListener注解处理器
        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }
        //org.springframework.context.event.internalEventListenerProcessor
        //内部管理的EventListenerFactory的bean名称
        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
        }
        return beanDefs;
    }
复制代码

 

1.2 EventListenerMethodProcessor和EventListenerFactory关系的建立

  EventListenerMethodProcessor会在容器启动时被注入到容器中,他是一个BeanFactoryPostProcessor

  EventListenerMethodProcessor和EventListenerFactory关系的建立,发生在其方法postProcessBeanFactory中

  EventListenerFactory的实例化时机只比BeanFactoryPostProcessor晚,比BeanPostProcessor实例化早

EventListenerMethodProcessor源码:

复制代码
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
    @Nullable
    private List<EventListenerFactory> eventListenerFactories;
    //初始化eventListenerFactories
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        //获取容器中所有的EventListenerFactory,并把他们实例化
        Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
        
        List<EventListenerFactory> factories = new ArrayList<>(beans.values());
        AnnotationAwareOrderComparator.sort(factories);
        //将EventListenerFactory储存到缓存eventListenerFactories中,便于后来使用
        this.eventListenerFactories = factories;
    }
}
复制代码

 

二、开始解析@EventListener

  EventListenerMethodProcessor是一个SmartInitializingSingleton,所以他会在所以bean实例化后,执行其afterSingletonsInstantiated方法

  注意:只有单例的SmartInitializingSingleton,才会执行其afterSingletonsInstantiated方法

2.1 基本流程

  获取容器中所有的类,把用 @Component 标注的类上所有的 @EventListener 方法用 EventListenerFactory 解析成一个 ApplicationListener

复制代码
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {

    @Override
    public void afterSingletonsInstantiated() {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        // 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~  一个一个的检查
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
             // 
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class<?> type = null;
                try {
                     // 防止是代理,吧真实的类型拿出来
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                }
                catch (Throwable ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("", ex);
                    }
                }
                if (type != null) {
                    // 对专门的作用域对象进行兼容~~~~(绝大部分都用不着)
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                                    beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                            if (targetClass != null) {
                                type = targetClass;
                            }
                        }
                        catch (Throwable ex) {
                            // An invalid scoped proxy arrangement - let's ignore it.
                            if (logger.isDebugEnabled()) {
                                logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                            }
                        }
                    }
                    try {
                        // 真正处理这个Bean里面的方法们。。。
                        processBean(beanName, type);
                    }
                    catch (Throwable ex) {
                        throw new BeanInitializationException("", ex);
                    }
                }
            }
        }
    }

    private void processBean(final String beanName, final Class<?> targetType) {
             //类上有@Component注解
            if (!this.nonAnnotatedClasses.contains(targetType) &&!targetType.getName().startsWith("java") &&!isSpringContainerClass(targetType)) {
                 Map<Method, EventListener> annotatedMethods = null;
                try {
                    //获取类中用@EventListener标注方法的信息
                    annotatedMethods = MethodIntrospector.selectMethods(targetType,
                            (MethodIntrospector.MetadataLookup<EventListener>) method ->
                                    AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
                }
                catch (Throwable ex) {
                    // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
                    }
                }
                //如果annotatedMethods为空,那代表类中没有用@EventListener标注的方法
                if (CollectionUtils.isEmpty(annotatedMethods)) {
                    this.nonAnnotatedClasses.add(targetType);
                    if (logger.isTraceEnabled()) {
                        logger.trace("" + targetType.getName());
                    }
                }
                else {
                    // 类中存在用@EventListener标注的方法
                    ConfigurableApplicationContext context = this.applicationContext;
                    Assert.state(context != null, "No ApplicationContext set");
                    //获取容器中所有EventListenerFactory
                    List<EventListenerFactory> factories = this.eventListenerFactories;
                    Assert.state(factories != null, "EventListenerFactory List not initialized");
                    for (Method method : annotatedMethods.keySet()) {
                        for (EventListenerFactory factory : factories) {
                            if (factory.supportsMethod(method)) {
                                // 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关)
                              // 这里注意:若你是JDK的代理类,请不要在实现类里书写@EventListener注解的监听器,否则会报错的。(CGLIB代理的木关系) 
                                Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); 

                                //利用EventListenerFactory创建ApplicationListener,详情后面说
                                ApplicationListener<?> applicationListener =
                                        factory.createApplicationListener(beanName, targetType, methodToUse);
                                //如果ApplicationListener是ApplicationListenerMethodAdapter类,那么执行其init方法
                                if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                    ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                                }
                                //放到容器中
                                context.addApplicationListener(applicationListener);
                                //@EventListener方法只能解析一次
                                break;
                            }
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug();
                    }
                }
            }
        }
}    
复制代码

注意:@EventListener方法只要有到一个可以解析他的EventListenerFactory,就不会让其他EventListenerFactory解析他了
所以如果容器中存在多个EventListenerFactory,我要注意他的顺序

2.2 EventListenerFactory解析@EventListener

EventListenerFactory 有2个实现类 DefaultEventListenerFactory 和 TransactionalEventListenerFactory

  DefaultEventListenerFactory:是处理 @EventListener,Spring默认就有

  TransactionalEventListenerFactory:是处理@TransactionalEventListener的,Spring默认是没有的,

  如果想要使用 @TransactionalEventListener 注解,就要注册一个TransactionalEventListenerFactory,也就是在启动类加上 @EnableTransactionManagement 注解

public interface EventListenerFactory {
    //是否支持当前方法
    boolean supportsMethod(Method method);
    //生成一个ApplicationListener
    ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);
}

DefaultEventListenerFactory实现类

复制代码
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
    private int order = LOWEST_PRECEDENCE;
    @Override
    public boolean supportsMethod(Method method) {
        return true;
    }
    @Override
    public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
        return new ApplicationListenerMethodAdapter(beanName, type, method);
    }

}
复制代码

ApplicationListenerMethodAdapter 中的一个 ApplicationListener,他是用来包装@EventListener标注的方法

复制代码
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {

    private final String beanName; //@EventListener方法所属bean的名字
    private final Method method;//@EventListener标注的方法
    private final Method targetMethod;//@EventListener标注的真实方法对象,防止其是代理方法
    //方法申明,如public void demo.Ball.applicationContextEvent(demo.OrderEvent)
    private final AnnotatedElementKey methodKey;
    private final List<ResolvableType> declaredEventTypes;//存储方法的参数
    private final String condition;//@EventListener的condition
    private final int order;
    private ApplicationContext applicationContext;
    private EventExpressionEvaluator evaluator;//@EventListener的EventExpressionEvaluator

    public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
        this.beanName = beanName;
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        this.targetMethod = (!Proxy.isProxyClass(targetClass) ?AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
        this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
        //获取方法上的@EventListener注解对象
        EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
        this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
        this.condition = (ann != null ? ann.condition() : null);
        this.order = resolveOrder(this.targetMethod);
    }

    public void onApplicationEvent(ApplicationEvent event) {
        processEvent(event);
    }
    
    public void processEvent(ApplicationEvent event) {
        Object[] args = resolveArguments(event);
        //根据@EventListener的condition,判断是否要处理
        if (shouldHandle(event, args)) {
            //调用方法
            Object result = doInvoke(args);
            if (result != null) {
                //如果有监听器可以监听这个结果,那么可以触发那个监听器
                handleResult(result);
            }
            else {
                logger.trace("No result object given - no result to handle");
            }
        }
    }
}
复制代码

 

posted on   凉小枫  阅读(485)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示