Spring EventListener注解原理及使用

文章目录

    • Spring @EventListener注解原理
      • 一、测试代码
      • 二、源码
        • 1、容器加载流程
        • 2、容器刷新流程
        • 3、原理
      • 三、使用

Spring @EventListener注解原理

一、测试代码

测试用例

public class SpringEventTest {
    @Test
    public void test_listener() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class);
        System.out.println("发布事件");
        TestEvent event = new TestEvent(new Object(), "事件1");
        context.publishEvent(event);
        context.close();
    }
}

config类

@Configuration
public class EventConfig {
    @EventListener
    public void listen(TestEvent event) {
        System.out.println("接收到事件:" + event);
    }
}

TestEvent类

public class TestEvent extends ApplicationEvent {
    private String name;
    public TestEvent(Object source, String name) {
        super(source);
        this.name = name;
    }
    public TestEvent(Object source) {
        super(source);
    }
    @Override
    public String toString() {
        return "TestEvent{name='" + name + '\'' + '}';
    }
}

二、源码

1、容器加载流程

public AnnotationConfigApplicationContext(String... basePackages) {
		this();
		scan(basePackages);
		refresh();
	}

2、容器刷新流程

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);
			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				// Initialize message source for this context.
				initMessageSource();
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				// Check for listener beans and register them.
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
				// Last step: publish corresponding event.
				finishRefresh();
			}catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}finally {
				resetCommonCaches();
			}
		}
	}

其中与EventListener有关联的步骤

  • initApplicationEventMulticaster(); 初始化事件多播器
  • registerListeners(); 注册Listener到多播器
  • finishBeanFactoryInitialization(beanFactory); 涉及将@EventListener转为普通Listener
    • preInstantiateSingletons();涉及将
    • afterSingletonsInstantiated();涉及
  • finishRefresh(); 发布容器刷新完成事件ContextRefreshedEvent

3、原理

原理:通过EventListenerMethodProcessor来处理@Eventlstener标记的方法,将其生成ApplicationListener(ApplicationListenerMethodAdapter)对象。在publishEvent时,通过getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType)函数,获取到ApplicationListener对象,通过反射调用方法。

public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware 

SmartInitializingSingleton什么时候执行呢

在Refresh()

  1. finishBeanFactoryInitialization(beanFactory);
  2. DefaultListableBeanFactory#preInstantiateSingletons:前半部分主要是遍历beanNames 创建Bean。创建完bean后判断各bean是不是SmartInitializingSingleton,如果是则执行 smartSingleton.afterSingletonsInstantiated()方法;
  3. EventListenerMethodProcessor#afterSingletonsInstantiated;
  4. EventListenerMethodProcessor#processBean;
  • 查找类中标注@EventListener的方法
  • EventListenerFactory.createApplicationListener(beanName, targetType, methodToUse) 构造listener
  • 添加listener到Context中
    - 如果有applicationEventMulticaster,添加到ApplicationContext.applicationEventMulticaster中
    - 如果没有applicationEventMulticaster,添加到ApplicationContext.applicationListeners中。
  1. AbstractApplicationContext#publishEvent
  2. SimpleApplicationEventMulticaster#multicastEvent
  3. ApplicationListenerMethodAdapter#onApplicationEvent
protected void processBean(
			final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
		//没有注解的class
		if (!this.nonAnnotatedClasses.contains(targetType)) {
			Map<Method, EventListener> annotatedMethods = null;
      //查找被注解EventListener的方法
			try {
				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 = getApplicationContext();
				for (Method method : annotatedMethods.keySet()) {
					for (EventListenerFactory factory : factories) {
						if (factory.supportsMethod(method)) {
							Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
              //创建applicationListener,通过Adapter将注解形式的listener转换为普通的listener
							ApplicationListener<?> applicationListener =
									factory.createApplicationListener(beanName, targetType, methodToUse);
							if (applicationListener instanceof ApplicationListenerMethodAdapter) {
								((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
							}
              //添加listner到applicationContext
							context.addApplicationListener(applicationListener);
							break;
						}
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" 						+beanName + "': " + annotatedMethods);
				}
			}
		}
	}

三、使用

  1. 与@Async注解一起使用,实现异步监听
     	@Async
        @EventListener
        public void listen(TestEvent event) {
            System.out.println(Thread.currentThread().getName() + "接收到事件:" + event);
        }
    
  2. 异步监听时,使用自定义的线程池
    注解方法
    @Async
    @EventListener("testTaskExecutor")
    public void listen(TestEvent event) {
        System.out.println(Thread.currentThread().getName() + "接收到事件:" + event);
    }
    
    线程池
    @Configuration
    public class TaskPoolConfig {
        @Bean("testTaskExecutor")
        public Executor sendMessageTaskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //核心线程数:线程池创建时候初始化的线程数
            //最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            //缓冲队列:用来缓冲执行任务的队列
            //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
            //线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(20);
            executor.setKeepAliveSeconds(60);
            executor.setThreadNamePrefix("testTaskExecutor-");
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            return executor;
        }
    }
    

你可能感兴趣的:(spring)