Spring 中的事件发布与监听

主要代码在org.springframework.contextorg.springframework.context.event包中

事件发布与监听主要包含以下角色:

  • 事件:ApplicationEvent
  • 事件监听器:ApplicationListener SmartApplicationListener GenericApplicationListener
  • 事件发布器:ApplicationEventPublisher
  • 事件广播器:ApplicationEventMulticaster

引入ApplicationListener有两种方式:

  • spring spi
  • 手动注入bean

手动注入bean有两种方式:

  • 类上注解@Component等注解+实现ApplicationListener接口
  • 类上注解@Component等注解+方法上注解@EventListener

案例如下:

// bean注入方式一,实现ApplicationListener+@Component注入bean
@Component
public class HelloEventListener implements SmartApplicationListener {
    
    
    
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    
    
        return false;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    
    

    }
}

// bean注入方式二,@EventListener+@Component
@Component
public class Test {
    
    

    @EventListener
    public void listen(Object obj){
    
    
        System.out.println("listening");
    }
     
    @EventListener(classes={
    
    ApplicationEvent.class},condition="springEL")
    public void listen(ApplicationEvent event){
    
    
        System.out.println("listening");
    }

}

关于@EventListener注解方法注入是通过EventListenerMethodProcessor的一个SmartInitializingSingleton,同时该类也是一个BeanFactoryPostProcessor,但扫描@EventListener方法和注入逻辑不在该接口的postProcess方法中,而是SmartInitializingSingleton接口的afterSingletonsInstantiated方法。

关于SmartInitializingSingleton的接口作用注释如下:

Callback interface triggered at the end of the singleton pre-instantiation phase during BeanFactory bootstrap. This interface can be implemented by singleton beans in order to perform some initialization after the regular singleton instantiation algorithm, avoiding side effects with accidental early initialization (e.g. from ListableBeanFactory.getBeansOfType calls). In that sense, it is an alternative to InitializingBean which gets triggered right at the end of a bean’s local construction phase.

看到其作用和 InitializingBean 类似,用于构造函数后的初始化操作,不过该接口是所有bean被创建之后被调用。在所有 bean的构造方法、初始化(@PostConstructInitializingBean)、BeanPostProcessor都执行完毕后再执行该接口方法,注意是所有bean都执行完这些方法。

Invoked right at the end of the singleton pre-instantiation phase, with a guarantee that all regular singleton beans have been created already.

public class EventListenerMethodProcessor
		implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
    
    

	// 负责设置EventListenerFactory
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
		// 回调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);
		// 设置eventListenerFactories
		this.eventListenerFactories = factories;
	}
	
	@Override
	public void afterSingletonsInstantiated() {
    
    
		...
		processBean(beanName, type);
		...
	}

	private void processBean(final String beanName, final Class<?> targetType) {
    
    
		
		if (
				// 不包含@EventListener的类的备忘录是否有该类型
				!this.nonAnnotatedClasses.contains(targetType) &&
				// 该类型的type, method or field 是否能被注解@EventListener
				AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
				// 不能是org.springframework开头的类,或者被注解了@Component,注意是或者
				!isSpringContainerClass(targetType)
			) {
    
    
			// 提取所有的方法
			Map<Method, EventListener> annotatedMethods = null;
			try {
    
    
				// ********MethodIntrospector.selectMethods********
				// 这里传入的是原始的class,所以对被代理的bean需要剖开找被代理的class
				// 找原始class通过AutoProxyUtils.determineTargetClass完成
				annotatedMethods = MethodIntrospector.selectMethods(targetType,
						(MethodIntrospector.MetadataLookup<EventListener>) method ->
								AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
			}
			...
			
			if (CollectionUtils.isEmpty(annotatedMethods)) {
    
    
				// 备忘录,加入已扫描的没有注解@EventListener的类
				this.nonAnnotatedClasses.add(targetType);
				...
			}
			else {
    
    
				// Non-empty set of methods
				ConfigurableApplicationContext context = this.applicationContext;
				Assert.state(context != null, "No ApplicationContext set");
				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)) {
    
    
							Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));	
							// 生成ApplicationListener
							ApplicationListener<?> applicationListener =
									factory.createApplicationListener(beanName, targetType, methodToUse);
							if (applicationListener instanceof ApplicationListenerMethodAdapter) {
    
    
								((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
							}
							context.addApplicationListener(applicationListener);
							break;
						}
	...

ApplicationListener监听到事件后的执行是同步过程,如果需要异步,可搭配@Async+@EventListener

方法注解处理套路

我们可以看到,注解了@EventListener的方法会被spring解析并生成一个ApplicationListener注入bean容器。
类似这种注解在方法上的处理方式,都可以采用以上的套路,即 :
假设我们要处理方法注解@Sample,在一个类中实现SmartInitializingSingleton接口,该类需要被注入容器,在SmartInitializingSingleton接口方法中使用MethodIntrospector::selectMethods

Map<Method, Sample> annotatedMethods = null;
// bean为要处理的类
annotatedMethods = MethodIntrospector.selectMethods( bean.getClass(),
						(MethodIntrospector.MetadataLookup<>) method ->
								AnnotatedElementUtils.findMergedAnnotation(method, Sample.class));
}
// 自定义处理
for (Map.Entry<Method, Sample> methodEntry : annotatedMethods.entrySet()) {
    
    
                Method executeMethod = methodEntry.getKey();
                Sample sample = methodEntry.getValue();
                ...
}

不仅@EventListener这么定义的,很多方法注解都是这个套路,如:XXL-JOB中定义任务的方法注解@XxlJob

事务消息监听器

spring-tx包下提供TransactionalApplicationListener接口和@TransactionalEventListener注解。

TransactionalApplicationListener接口:An ApplicationListener that is invoked according to a TransactionPhase. NOTE: Transactional event listeners only work with thread-bound transactions managed by a PlatformTransactionManager.

猜你喜欢

转载自blog.csdn.net/weixin_41866717/article/details/129628321