• Spring源码篇(十二)事件机制


    前言

    事件的应用在开发中也是比较灵活的一个方式,可以做到代码解耦,这个篇章就探究事件的发布订阅的原理,本篇原理比较简单,但代码结构较为复杂,所以如果只想了解事件机制原理,添加监听器的前面部分可以简单了解就行。

    应用示例

    第一种:@EventListener

    注解方式的监听事件

    定义一个事件如下,但是需要注意的是不一定需要继承ApplicationEvent,任何对象都可以,并且@EventListener注解的方法可以private修饰

    public class CusEvent extends ApplicationEvent {
    
        private String id;
    
        public CusEvent(Object source) {
            super(source);
        }
    
        public CusEvent(Object source, String id) {
            this(source);
            this.id = id;
        }
    
        public String getId() {
            return id;
        }
    }
    
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    定义一个监听的方法

    @Component
    public class CusService {
    
        @EventListener
        public Object get(CusEvent event) {
            System.out.println("eventListener 监听到事件");
            return true;
        }
        
        // 或者也可以这样,和上面是一样的
        @EventListener(CusEvent.class)
        public Object get() {
            System.out.println("eventListener 监听到事件 2");
            return true;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    发布一个事件

    @Component
    public class EventAppRunner implements ApplicationRunner {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            applicationContext.publishEvent(new CusEvent(this, "1"));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    第二种:实现ApplicationListener

    public class CusEvent extends ApplicationEvent {
    
        private String id;
    
        public CusEvent(Object source) {
            super(source);
        }
    
        public CusEvent(Object source, String id) {
            this(source);
            this.id = id;
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    继承ApplicationListener,这个是spring提供的监听类;

    这里有一个注意点,它是泛型的,泛型类型是我们定义的事件类,如果没有这个泛型,那么就是默认的ApplicationEvent事件,那么发布的事件,都会被监听到

    @Component
    public class CusEventListener implements ApplicationListener<CusEvent> {
        @Override
        public void onApplicationEvent(CusEvent event) {
            System.out.println("自定义事件监听器 监听到事件");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第三种:@TransactionalEventListener

    这第三种方式是支持事务的,需要引入spring-data的依赖

      		<dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-jdbcartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4

    使用就是注解不一样就行了

        @TransactionalEventListener
        public Object get2(CusEvent event) {
            System.out.println("TransactionalEventListener 监听到事件");
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    补充:筛选条件

    除此之外,它还支持条件筛选,如下是EventListener的定义,它有一个属性condition它支持el表达式

    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EventListener {
    
    	@AliasFor("classes")
    	Class<?>[] value() default {};
    
    
    	@AliasFor("value")
    	Class<?>[] classes() default {};
    
    	String condition() default "";
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    那下面我们可以尝试以下:

    // 这个是当我们发布的事件对象中的id='1'时,才会触发
    	@EventListener(condition = "#event.id == '1'")
        public Object get3(CusEvent event) {
            System.out.println("eventListener条件 监听到事件 - ID=1");
            return true;
        }
    
        @EventListener(condition = "#event.id == '2'")
        public Object get4(CusEvent event) {
            System.out.println("eventListener条件 监听到事件 - ID=2");
            return true;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    也可以尝试枚举变量

        @EventListener(condition = "T(com.liry.event.CusConst).WORD.name()  == #event.id")
        public Object get5(CusEvent event) {
            System.out.println("eventListener条件 监听到事件 - ID=2");
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果你使用的是TransactionalEventListener,它额外提供了属性phase这个是用于事务传播机制的;

    它提供了:

    # 事务提交前执行
    BEFORE_COMMIT
    # 事务提交后执行
    AFTER_COMMIT
    # 事务回滚后执行
    AFTER_ROLLBACK
    # 事务完成后
    AFTER_COMPLETION
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    用法如下:

        @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
        public Object get6(CusEvent event) {
            System.out.println("TransactionalEventListener事务 监听到事件");
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    源码

    事件机制的原理也算简单,它使用了观察者模式,可以理解为在spring容器中它保存着一个监听器的列表,当我们发布事件时,就遍历这个列表,然后逐个判断是否符合条件,符合条件就执行监听器方法。

    我们先来看一段代码:

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    		Assert.notNull(event, "Event must not be null");
    
        // 这里直接看的话,就是对事件的封装
    		ApplicationEvent applicationEvent;
    		if (event instanceof ApplicationEvent) {
    			applicationEvent = (ApplicationEvent) event;
    		}
    		else {
    			applicationEvent = new PayloadApplicationEvent<>(this, event);
    			if (eventType == null) {
    				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
    			}
    		}
    
        // 然后添加了事件
    		if (this.earlyApplicationEvents != null) {
    			this.earlyApplicationEvents.add(applicationEvent);
    		}
    		else {
                // 或者执行
    			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    		}
    
        // 以及父容器的执行
    		if (this.parent != null) {
    			if (this.parent instanceof AbstractApplicationContext) {
    				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    			}
    			else {
    				this.parent.publishEvent(event);
    			}
    		}
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    通过这段代码,我们就已经出现了几个问题:

    1. 为何要进行事件的封装?
    2. 为什么要把容器放到一个容器里(earlyApplicationEvents),不直接执行?
    3. 执行用的ApplicationEventMulticaster在哪里初始化?
    4. 以及ApplicationEventMulticaster它怎样执行事件?

    初始化事件器

    位置:org.springframework.context.support.AbstractApplicationContext#refresh

    这里ApplicationEventMulticaster我这里叫做事件器,按照名字翻译叫事件广播器,我下面的都叫事件器;我们所使用的事件器是在spring初始化中做的:

    image-20231012215019682

    	protected void initApplicationEventMulticaster() {
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            // 判断spring容器中是否已经有了事件器bean
            // 一般是不存在的
    		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
                // 若存在,则将spring容器中的事件器bean赋给当前的属性变量
    			this.applicationEventMulticaster =
    					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    			}
    		}
    		else {
                // 如果在spring容器中不存在事件器bean,那么这里new一个
    			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
                // 然后将这个new出来的事件器,注册到spring容器中
    			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
    						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    			}
    		}
    	} 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这一个步骤是在AbstractApplicationContext中做的,所以this.applicationEventMulticaster就是 Application Context的属性,我们可以直接通过ApplicationContext发布事件。

    那为什么在方法中会先从bean容器中获取这个事件器呢?

    这个我的理解是这样的:

    这个init方法在bean容器之后、也在bean扫描之后,所以可能存在我们自定义的一个事件器,因为这个过程中,我们可以通过beanFactoryPostProcessor,或者是beanPostProcessor,也或者是beanRegister进行添加,所以这个就相当于是将我们自定义的bean优先级提高。

    注册监听器

    上一步是初始化了事件器,那么在执行事件前,它还需要添加监听器,才能执行监听器的方法。

    image-20231012223059702

    	protected void registerListeners() {
    		// 1. 静态指定的监听器:显示声明,如add(new Listener())
    		for (ApplicationListener<?> listener : getApplicationListeners()) {
    			getApplicationEventMulticaster().addApplicationListener(listener);
    		}
    
    		// 2. spring扫描得到的bean,如import ApplicationListener
    		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    		for (String listenerBeanName : listenerBeanNames) {
                // 这里添加的是bean的名称,因为这里还并没有实例化
    			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    		}
    
    		// 3. 执行早期的事件,也就是容器准备好之前的事件
    		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    		this.earlyApplicationEvents = null;
    		if (earlyEventsToProcess != null) {
    			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
    				getApplicationEventMulticaster().multicastEvent(earlyEvent);
    			}
    		}
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注册监听器这一段中,分了两种方式添加监听器:

    1. 静态指定:显示的声明添加,如add(new Listener())
    2. Spring扫描得到的监听器bean,如import ApplicationListener

    这里要注意的一点是,这里添加的是bean的名称

    第三点中,它执行了监听器:

    image-20231021141728883

    这里,他是先进行了复制,然后earlyApplicationEvents置空,这里的这个属性是作为一个判断条件来用的,当不为空时,表示存在应用准备前期的事件,需要执行,因为现在才完成初始化,所以现在执行。

    添加监听器

    上面说过监听器的添加有两种,一种是静态指定(显示声明),另一种是spring扫描添加。

    我们还是先找到注册监听器的位置:

    org.springframework.context.support.AbstractApplicationContext#registerListeners

    这里getApplicationListeners()它获取的是当前实例对象(ApplicationContext)的属性this.applicationListeners,并且针对这个属性有add方法,也就是说,只要能拿到ApplicationContext对象都可以调用add方法:addApplicationListener

    添加1:应用启动前的监听器

    这里添加步骤:

    1. SpringApplication实例化时,获取spring.factories里的监听器,添加到listeners
    2. SpringApplication.run方法中:prepareContext时添加到applicationListeners
    3. SpringApplication.run方法中:refresh时添加到earlyApplicationListeners,在close时调用
    SpringApplication实例化时

    主程序如下:

    @SpringBootApplication
    public class EventApp {
        public static void main(String[] args) {
            SpringApplication.run(EventApp.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么它会默认读取spring.factories文件中key为org.springframework.context.ApplicationListener的监听器全类名,这里一般会有11个(一般简单的SpringBoot程序),这时添加的监听器是在application.listener

    image-20231021095948788

    SpringApplication.run

    prepareContext中,存在很多ApplicationContextInitializer应用初始化器,他们都会注册一个自己的监听器进行事件发布

    image-20231020212018227

    image-20231021101400475

    image-20231021095628177

    image-20231021095538232

    image-20231021102012975

    这两个地方是应用初始化器自己添加监听器,和从spring.factories文件读取的监听器,需要注意的是,在这里这些获取到的监听器都只是保持在一个ApplicationContext的属性applicationListeners中。

    refresh

    这里就是将启动前所有的监听器(上一步)都添加到earlyApplicationListeners,表示这个是早期的监听器。

    image-20231021102921526

    添加2:ApplicationListener实现类

    这里的步骤是:

    1. 添加一个bean后置处理器ApplicationListenerDetector

    2. 在bean生命周期之后,会执行后置处理器的回调方法,添加监听器的

    3. 添加后置处理器ApplicationListenerDetector

    Spring在准备bean容器时,会添加默认的处理器和解析器,可以理解为这里添加的都是spring会执行,或者用到的必须的一些配置;

    首先这在这里它会添加一个后置处理器·ApplicatonListenerDetector

    位置:org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory

    image-20231020212953924

    1. 执行后置处理器的回调方法

    后置处理器执行的位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

    image-20231020213300542

    添加监听器的位置:

    org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization

    image-20231021140908103

    可以看到,它这里判断是ApplicationListener类型,也就是说只要我们的bean实现了ApplicationListener接口,就会被添加到事件器。

    添加3:@EventListener

    相对于接口来说,注解方式的更为简便,其实就是将有注解的方法保存,然后在执行的时候进行反射执行,外部再套一个封装类就完成了,下面来看一下这个过程。

    1. 所有的bean初始化完毕
    2. 执行SmartInitializingSingleton接口回调
    3. 便利bean,查找含有@EventListener注解的类,并解析
    4. 通过bean对象,和解析出来的方法对象,通过监听器工厂类构建一个新的监听器封装类ApplicationListenerMethodAdapter

    看这个位置:

    org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

    image-20231021153456727

    这个地方就是添加注解方式的监听器的地方,所有实现SmartInitializingSingleton的类都会被执行,而处理注解式监听器就是由实现了这个接口的类EventListenerMethodProcessor完成,

    简单看下的代码:

    @Override
    	public void afterSingletonsInstantiated() {
            // 获取bean容器
    		ConfigurableListableBeanFactory beanFactory = this.beanFactory;
    		Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
            // 遍历所有的beanname
    		String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
    		for (String beanName : beanNames) {
                // 判断是否是原型bean,只有单例bean才进行此操作
    			if (!ScopedProxyUtils.isScopedTarget(beanName)) {
    				Class<?> type = null;
    				try {
                        // 获取bean的原始类型,因为存在动态代理,代理过的对象直接获取的类型并不是原始类型
    					type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
    				}
    				catch (Throwable ex) {
    					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
    					if (logger.isDebugEnabled()) {
    						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
    					}
    				}
    				if (type != null) {
                        // 这里再次进行了校验,ScopedObject是spring内部类,作用域对象
                        // 它这里应该是在ScopedObject对象中不应该有监听器类,所以这里在获取了一次
    					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 {
                            // 这里是真正构建监听器封装类的地方
    						processBean(beanName, type);
    					}
    					catch (Throwable ex) {
    						throw new BeanInitializationException("Failed to process @EventListener " +
    								"annotation on bean with name '" + beanName + "'", ex);
    					}
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    	private void processBean(final String beanName, final Class<?> targetType) {
            // 没有解析过,含有@EventListener注解,并且是一个bean(也就是有@Component注解)
    		if (!this.nonAnnotatedClasses.contains(targetType) &&
    				AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
    				!isSpringContainerClass(targetType)) {
    
    			Map<Method, EventListener> annotatedMethods = null;
    			try {
                    // 从指定class中获取到被注解@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);
    				}
    			}
    
                // 如果没有获取到方法就结束
    			if (CollectionUtils.isEmpty(annotatedMethods)) {
    				this.nonAnnotatedClasses.add(targetType);
    				if (logger.isTraceEnabled()) {
    					logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
    				}
    			}
    			else {
    				// Non-empty set of methods
    				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");
                    // 便利@EventListener注解的方法
                    // 每一个方法都应该创建一个监听器
    				for (Method method : annotatedMethods.keySet()) {
    					for (EventListenerFactory factory : factories) {
                            // 这里是工厂方法一般有的一个支持接口
                            // 用于判断当前这个工厂类是否支持这个方法
    						if (factory.supportsMethod(method)) {
                                // 这里类似判断
                                // 里面做了校验: private修饰的实例方法,并且是SpringProxy实现类,就报异常
                                // 这说明了什么问题?
                                // 说明了@EventListener它支持private修饰的方法
    							Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                                // 通过工厂方法创建一个监听器封装类,参数就是beanName,class,方法对象
    							ApplicationListener<?> applicationListener =
    									factory.createApplicationListener(beanName, targetType, methodToUse);
                                // 这里的这个判断,类似于适配扩展功能,因为我们可能会定义自己的一个工厂类
    							if (applicationListener instanceof ApplicationListenerMethodAdapter) {
    								((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
    							}
                                // 将创建的监听器封装类添加到事件器中
    							context.addApplicationListener(applicationListener);
    							break;
    						}
    					}
    				}
    				if (logger.isDebugEnabled()) {
    					logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
    							beanName + "': " + annotatedMethods);
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    添加事件监听器工厂类,如果你没有引入spring-boot-starter-jdbc依赖,那么只有一个DefaultEventListenerFactory这个就是创建@EventListener监听器的工厂类

    image-20231021163720775

    添加4:@TransactionalEventListener

    @EventListener封装的地方一样,只是他们所使用工厂类不一样,工厂类TransactionalEventListenerFactory创建ApplicationListenerMethodTransactionalAdapter

    位置:org.springframework.context.event.EventListenerMethodProcessor#processBean

    image-20231021193011975

    发布事件/执行事件

    首先发布事件的类需要实现ApplicationEventPublisher接口,ApplicationContext也实现了这个一个接口,所以可以通过ApplicatoinContext进行事件发布。

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    		Assert.notNull(event, "Event must not be null");
    
    		// 这里做发布事件的判别
        // 当我们传入的事件event并非是ApplicationEvent时,它会进行一个事件对象的封装
    		ApplicationEvent applicationEvent;
    		if (event instanceof ApplicationEvent) {
    			applicationEvent = (ApplicationEvent) event;
    		}
    		else {
                // 非applicationEvent类,进行封装
    			applicationEvent = new PayloadApplicationEvent<>(this, event);
    			if (eventType == null) {
    				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
    			}
    		}
    
    		// 那这里的判空,不难理解,在spring启动过程中,它会经过很多的步骤,每个步骤都有可能发布事件,但是在spring容器准备好之前都是不能发布事件的,
        // 而这里的意思就是在准备好之前,所发布的事件都会添加到earlyApplicationEvents这个容器中,待容器准备好后,在执行这些事件
    		if (this.earlyApplicationEvents != null) {
    			this.earlyApplicationEvents.add(applicationEvent);
    		}
    		else {
                // 没有暂存的事件,就执行执行事件
    			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    		}
    
    		// 如果父容器存在,就会进行父容器的事件发布
    		if (this.parent != null) {
    			if (this.parent instanceof AbstractApplicationContext) {
    				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    			}
    			else {
    				this.parent.publishEvent(event);
    			}
    		}
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    这里我们讨论下这段代码:

    		if (this.earlyApplicationEvents != null) {
    			this.earlyApplicationEvents.add(applicationEvent);
    		}
    		else {
                // 没有暂存的事件,就执行执行事件
    			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这段就是为了处理在准备前发布的事件,但是在registerListener方法中已经清理过了,我们可以这样理解

    1. 所有的方法都会通过publishEvent进行事件发布,那么就是调用上面的方法,如果是在容器准备之前,那么就是执行this.earlyApplicationEvents.add(applicationEvent);
    2. 然后走到registerListener然后清空前期事件
    3. 之后spring启动过程中再发事件,就走getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

    image-20231021200435568

    下面,那我们来看getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

    位置:org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

    	@Override
    	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
            // 获取事件类型
    		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
            // 这里是获取一个执行器,我们可以设置一个我们自定义的一个线城池
            // 这里默认是null
    		Executor executor = getTaskExecutor();
            // getApplicationListeners 其实做了一个缓存,根据事件类型进行监听器的缓存
            // 第一次是从bean容器获取的,之后都是从缓存中获取
    		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    			if (executor != null) {
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
    				invokeListener(listener, event);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    @TransactionalEventListener与@EventListener

    这两个的区别在于,一个可以保证同步执行,一个保证同步执行同时,保证事务的传播;

    @TransactionalEventListener执行的代码,位置:org.springframework.transaction.event.ApplicationListenerMethodTransactionalAdapter#onApplicationEvent

    	@Override
    	public void onApplicationEvent(ApplicationEvent event) {
    		if (TransactionSynchronizationManager.isSynchronizationActive() &&
    				TransactionSynchronizationManager.isActualTransactionActive()) {
    			TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
    			TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
    		}
    		else if (this.annotation.fallbackExecution()) {
    			if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
    				logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
    			}
    			processEvent(event);
    		}
    		else {
    			// No transactional event execution at all
    			if (logger.isDebugEnabled()) {
    				logger.debug("No transaction is active - skipping " + event);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    之前在事务原理篇中解析过,spring保证事务的传播,是有一个事务管理器,它在线程缓存中保持了会话connection,通过dataSource获取,并且事务的提交回滚都是由TransactionSynchronizationManager这个类进行管理,我们看一段提交的代码:

    	public static void triggerBeforeCommit(boolean readOnly) {
    		for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
    			synchronization.beforeCommit(readOnly);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里它其实是获取了所有的TransactionSynchronization类,在开启事务和提交事务时,都是获取到这个对象,然后通过这个对象进行开启事务和事务提交,所以这个类就类似一个事务的回调方法,在开启事务和提交事务这些操作,都会调用实现类。

    image-20231021205552589

    image-20231021205611033

    image-20231021205634158

    呐,这里的代码就和ApplicationListenerMethodTransactionalAdapter执行的相似。

    总结

    1. 发布的事件对象可以是实现了ApplicationEvent接口的实现类,也可以是随意的一个对象
    2. 它的底层原理就是一个监听器集合,在发布事件后,遍历监听器,判别适合的监听器,然后执行
    3. 我们可以自定义自己的监听器工厂类:
      1. 自定义监听器注解,如:@CustomEventListener
      2. 实现一个监听器工厂类:CustomEventListenerFactory implement EventListenerFactory
      3. 构建一个ApplicationListenerMethodAdapter监听器对象
      4. 添加到事件器中
    4. 使用@EventListener不一定要public修饰,private也是生效的
    5. 事件对象不一定要实现ApplicationEvent
    6. 可以在spring.factories添加监听器类
  • 相关阅读:
    MFC 学习笔记
    QML + KDDockWidget 实现 tabwidget效果( 窗口可独立浮动和缩放)
    Java日志框架的扛把子 - SLF4J - SLF4J的原理和实践
    高等数学(第七版)同济大学 习题1-10 个人解答
    Linux系统中输入设备的应用编程实现
    解决element ui Table 最后的数据没有子数据也有展开按钮的问题
    这篇文章让你实现时光机特效的操作
    阿里巴巴淘口令API的安全保障措施在电商领域的应用与实践
    PID控制算法
    【R语言数据科学】(十八):系统聚类和K-Means聚类
  • 原文地址:https://blog.csdn.net/qq_28911061/article/details/133998436