Spring 监听机制实现和源码剖析

目录

1、使用Spring 事件

(1)事件

(2)事件监听器

(3)事件发布操作

(4)监听器使用的相关问题

2、Spring事件原理

3、源码流程

(1)前期准备

(2)事件多播器的初始化

(3)注册事件监听器,发布早期事件

(4)发布Spring内置事件


1、使用Spring 事件

Spring事件体系包括三个组件:事件,事件监听器,事件广播器。

(1)事件

Spring内置事件

内置事件中由系统内部进行发布,只需注入监听器

Event

说明

ContextRefreshedEvent

当容器被实例化或refreshed时发布。如调用refresh()方法,此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化,所有的容器对象都已准备好可使用。如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)

ContextStartedEvent

当容器启动时发布,即调用start()方法,已启用意味着所有的Lifecycle bean都已显式接收到了start信号

ContextStoppedEvent

当容器停止时发布,即调用stop()方法,即所有的Lifecycle bean都已显式接收到了stop信号,关闭的容器可以通过start()方法重启

ContextClosedEvent

当容器关闭时发布,即调用close方法,关闭意味着所有的单例bean都已被销毁。关闭的容器不能被重启或refresh

RequestHandledEvent

这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布

自定义事件

事件类需要继承ApplicationEvent,代码如下:

import org.springframework.context.ApplicationEvent;
/***
 * 自定义事件
 */
public class OrderEvent extends ApplicationEvent {
	private String name;
	public OrderEvent(Object source, String name) {
		super(source);
		this.name = name;
	}
	public String getName() {
		return name;
	}
}

这里为了简单测试,所以写的很简单。事件类是一种很简单的pojo,除了需要继承ApplicationEvent 也没什么了,这个类有一个构造方法需要super。

(2)事件监听器

事件监听器 -> 基于接口

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/***
 * 监听器->观察者模式
 */
@Component
public class OrderEventListener implements ApplicationListener<OrderEvent> {
	public void onApplicationEvent(OrderEvent event) {
		if (event.getName().equals("reduce_stock")) {
			System.out.println("减库存.......");
		}
	}
}

事件监听器需要实现ApplicationListener接口,这是个泛型接口,泛型类类型就是事件类型。其次需要是spring容器托管的bean,所以这里加了@component,只有一个方法,就是onApplicationEvent。

事件监听器 -> 基于注解

@Component
public class OrderEventListener {
	// 基于注解的监听器
	@EventListener(OrderEvent.class)
	public void onApplicationEvent(OrderEvent event) {
		if (event.getName().equals("reduce_stock")) {
			System.out.println("减库存.......");
		}
	}
}

(3)事件发布操作

事件发布方式很简单,调用AnnotationConfigApplicationContext.publishEvent()方法

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainClass {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
		//下单
		Order order =new Order();
		System.out.println("下单");
		// 发布订单事件 -> 减库存
		ctx.publishEvent(new OrderEvent(order,"reduce_stock"));
		System.out.println("日志...");
	}
}

执行结果

补充发布事件中使用到的两个类:Order.java,MainConfig.java

public class Order {
    private Integer id;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.swadian.task.event"})
//@EnableAsync  异步事件
public class MainConfig {
}

(4)监听器使用的相关问题

1.同样的事件能有多个监听器吗? -- 可以

2.事件监听器一定要写一个类去实现吗?

可以不需要,spring有个注解@EventListener,修饰在方法上,该方法就可以作为一个事件的监听器

@Component
public class OrderEventListener {
	// 基于注解的监听器
	@EventListener(OrderEvent.class)
	public void eventListener(OrderEvent event) {
		if (event.getName().equals("reduce_stock")) {
			System.out.println("减库存.......");
		}
	}
}

3.事件监听操作和发布事件的操作是同步的吗?

是的,所以如果有事务,监听操作也在事务内

4.事件监听操作可以异步处理吗?

可以,默认同步。如果需要异步,可以向多播器中(SimpleApplicationEventMulticaster)设置一个TaskExecutor

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@ComponentScan(basePackages = {"com.swadian.task.event"})
@EnableAsync  //异步事件
public class MainConfig {
	/**
	 * 往SimpleApplicationEventMulticaster设置taskExecutor则为异步事件
	 * 或者使用@Async
	 * @return
	 */
    @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster
                = new SimpleApplicationEventMulticaster();
        // ThreadPoolTaskExecutor -> 设置异步线程
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

设置的TaskExecutor,会在源码里用到

2、Spring事件原理

原理:观察者模式

Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster(多播器)的角色负责把事件转发给监听者,工作流程如下:

发布者调用applicationEventPublisher.publishEvent(msg);将事件发送给了EventMultiCaster,然后由EventMultiCaster注册所有的Listener(监听者),最后根据事件类型决定转发给哪个Listener。

3、源码流程

 (1)前期准备

Spring在AbstractApplicationContext.refresh()容器启动方法中搭建了事件的基础设施。refresh()方法的具体实现如下:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1-准备刷新上下文环境 -> 声明不需要手动发布的早期监听器+事件
			prepareRefresh();
			// 2-告诉子类刷新内部bean工厂——>不同的工厂有不同的实现(XML和注解方式)
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 3-对bean工厂进行填充属性 -> 注册监听器的解析器ApplicationListenerDetector
			prepareBeanFactory(beanFactory);
			try {
				// 4-允许在上下文子类中对bean工厂进行后处理 -> 空方法,子类实现
				postProcessBeanFactory(beanFactory);
				// 5-调用在上下文中注册的Bean工厂后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				// 6-注册拦截bean创建的bean后置处理器
				registerBeanPostProcessors(beanFactory);
				// 7-为此上下文初始化消息源-国际化
				initMessageSource();
				// 8-为此上下文初始化事件多播 -> 所有的监听器都会注册到多播器里边,由多播器调用
				initApplicationEventMulticaster();
				// 9-初始化特定上下文子类中的其他特殊bean -> 空方法,留给其他容器进行拓展
				onRefresh();
				// 10-注册事件监听器
				registerListeners();
				// 11-实例化所有剩余的(非惰性初始化)单例。
				finishBeanFactoryInitialization(beanFactory);
				// 12-最后一步:刷新容器,发布相应的事件。
				finishRefresh();
			}
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				// 销毁已经创建的单例以避免悬空的资源。
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				// 重置Spring核心中常见的内省缓存,因为我们可能不再需要单例bean的元数据了。
				resetCommonCaches();
			}
		}
    }

在prepareRefresh()方法中,添加了早期监听器和早期监听器事件,早期监听器和事件不需要手动发布,在 refresh() 方法中,调用 registerListeners() 会自动进行发布。

protected void prepareRefresh() {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		// 容器费关闭状态
		this.closed.set(false);
		// 容器激活 ——> 只有调用refresh()才能够激活,然后才能getBean()
		this.active.set(true);
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}
		// 默认为空 ——> 拓展用
		initPropertySources();
		// 验证initPropertySources()中的必须属性,和initPropertySources()一起使用
		getEnvironment().validateRequiredProperties();
		// 创建一个早期的事件监听器earlyApplicationListeners
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// 添加早期的事件监听器
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// 早期监听事件 earlyApplicationEvents
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

AbstractApplicationContext拥有一个applicationListeners成员变量,用于添加早期监听器

(2)事件多播器的初始化

refresh() -> initApplicationEventMulticaster()

用户可以在配置文件中为容器定义一个自定义的事件多播器,只要实现ApplicationEventMulticaster 就可以了,Spring会通过反射的机制将其注册成容器的事件多播器。如果没有找到配置的外部事件多播器,Spring自动使用 SimpleApplicationEventMulticaster作为默认的事件多播器

(3)注册事件监听器,发布早期事件

refresh() -> registerListeners()

Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry 中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。 

AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。

(4)发布Spring内置事件

refresh() -> finishRefresh()

如果是自定义的监听事件发布,也是需要调用 publishEvent() 的方法;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainClass {
	public static void main(String[] args) throws InterruptedException {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
		//下单
		Order order =new Order();
		System.out.println("下单");
		// 发布订单自定义事件 -> 调用publishEvent()
		ctx.publishEvent(new OrderEvent(order,"reduce_stock"));
		Thread.sleep(2000);
		System.out.println("日志...");
	}
}

进入AbstractApplicationContext.publishEvent() 方法,会获取一个多播器,然后去发布事件

如果没有设置用户自定义的多播器,那么会使用默认多播器 SimpleApplicationEventMulticaster, 在多播器SimpleApplicationEventMulticaster中会去调用事件监听器

有没有发现,这个方法,正是我们自定义监听器时实现 ApplicationListener 接口,重写的那个onApplicationEvent()方法

至此,通过接口方式的实现的监听器解析步骤源码就分析结束了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring监听器是一种应用于Spring容器的扩展机制,用于监听Spring容器中的事件,当事件发生时执行相应的处理逻辑。Spring监听器可以监听容器中的各种事件,如容器初始化、容器销毁、Bean初始化、Bean销毁等。 创建Spring监听器的方式有两种: 1. 实现ApplicationListener接口 创建一个类实现ApplicationListener接口,并实现onApplicationEvent方法,该方法会在监听到对应的事件时被调用,可以在该方法中编写相应的处理逻辑。 例如: ```java @Component public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) { // 处理逻辑 } } ``` 2. 使用@EventListener注解 在方法上添加@EventListener注解,该方法会在监听到对应的事件时被调用,可以在该方法中编写相应的处理逻辑。 例如: ```java @Component public class MyEventListener { @EventListener public void handleMyEvent(MyApplicationEvent event) { // 处理逻辑 } } ``` Spring监听器的作用和使用: 1. 监听容器事件 Spring监听器可以监听容器初始化、容器销毁等事件,可以在事件发生时执行相应的处理逻辑,如打印日志、清理资等。 2. 监听Bean事件 Spring监听器可以监听Bean初始化、Bean销毁等事件,可以在事件发生时执行相应的处理逻辑,如对Bean进行初始化、销毁前的清理等。 3. 监听自定义事件 Spring监听器可以监听自定义事件,可以在事件发生时执行相应的处理逻辑,如处理用户注册事件、处理订单支付事件等。 总之,Spring监听器是一个非常实用的扩展机制,可以方便地监听Spring容器中的各种事件,并进行相应的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值