文章目录
事件机制的优势
解耦:用事件机制添加多个业务逻辑操作,不需要与现有的业务逻辑耦合在一起,实现单一职责。在需要的时候还可以很方便的添加或去除一些业务操作,或者将业务操作用其他服务实现异步化。
举例:用户注册成功,系统现有两个后续业务操作:短信通知和邮件通知,这时候就可以用不同监听器去执行,两个操作互不影响,还可以异步执行。
附(劣势):解耦意味着更多业务处理类的加入,维护时需要注意遗漏;异步则需要考虑是否有事务要求,以及执行失败的处理。
1. 事件机制
1.1 事件
AbstractEvent,内部 source字段表示事件源,一般自定义事件去继承这个抽象父类。
public abstract class AbstractEvent {
protected Object source;
public AbstractEvent(Object source) {
this.source = source;
}
}
1.2 事件监听
EventListener,事件监听的接口,自定义的事件监听器实现这个接口,通过实现 onEvent 方法处理自定义事件。
// 事件监听器,E表示监听器感兴趣的事件类型
public interface EventListener<E extends AbstractEvent>{
// 处理事件的方法
void onEvent(E event);
}
1.3 事件发布(广播)
EventMulticaster
- 事件监听器的管理(注册/移除监听器,将监听器和事件关联起来)
- 事件广播(将事件广播给所有的监听器,调度感兴趣的监听器处理事件)
public interface EventMulticaster {
// 广播事件给监听器,对该事件感兴趣的监听器会执行处理(遍历监听器的集合等方式,调用相应监听器的onEvent[或者异步调用])
void multicastEvent(AbstractEvent event);
// 添加事件监听器(一般放入链表等集合中)
void addEventListener(EventListener<?listener);
// 移除事件监听器
void removeEventListener(EventListener<?listener);
}
2. Spring 实现
Spring事件机制是观察者模式的一种实现,是除了事件源和监听者两个角色之外,还有一个
EventMultiCaster
的角色负责把事件转发(广播)给监听者。
2.1 相应 API
事件
ApplicationEvent
public abstract class ApplicationEvent extends EventObject {
/** System time when the event happened. */
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
}
事件监听
Spring 创建事件监听器并注册到广播器上有两种方式,实现 ApplicationListener 、使用 @EventListener 注解。
spring4.2 版本之后,提供 @EventListener 注解用于 public 方式,自定义事件作为形参可以直接注册为监听器。
注:两种方式的 Listener 都需要用 Spring 管理 Bean 才行。
注2:如果被 @EventListener 标注的方法返回一个 Event,那么 Spring 将继续发布此 event。
- 事件监听1 ApplicationListener
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/** Handle an application event. */
void onApplicationEvent(E event);
}
- 事件监听2 @EventListener
@Component
public class AnnotationDrivenContextStartedListener {
/** 注册的事件就是 HelloEvent,onEvent的处理是 messageListener 方法 */
@EventListener(HelloEvent.class)
public void messageListener(HelloEvent helloEvent){
System.out.println("AnnotationDrivenContextStartedListener:"+helloEvent.message);
}
}
事件发布
Spring 发布事件有两种方式,方式一是实现 ApplicationContextAware或实现 ApplicationEventPublisherAware,方式二是使用 @EventListener。
注:本质上是一致的,ApplicationContextAware 获取到 ApplicationContext,ApplicationContext 继承了 ApplicationEventPublisher;ApplicationEventPublisherAware 直接获取到 ApplicationEventPublisher。
- 事件发布1 ApplicationContextAware
public interface ApplicationContextAware extends Aware {
/** 获取一个 ApplicationContext,用这个对象来执行发布 */
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
- 事件发布2 ApplicationEventPublisherAware
public interface ApplicationEventPublisherAware extends Aware {
/** 获取一个 ApplicationEventPublisher,用这个对象来执行发布{这个对象是否也是ApplicationContext?待验证} */
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
ApplicationContext、ApplicationEventPublisher
// 继承了 ApplicationEventPublisher
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// ...
}
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 发布/广播事件(AbstractApplicationContext 会执行 EventMulticaster.multicastEvent(event))
void publishEvent(Object event);
}
2.2 继承 ApplicationListener 注册实现分析
org.springframework.context.support.AbstractApplicationContext#addApplicationListener
执行调用分析:
refresh -> finishBeanFactoryInitialization -> ... -> getBean -> ... -> doCreateBean -> initializeBean -> ... -> postProcessAfterInitalization -> addApplicationListener
注1:
finishBeanFactoryInitialization 这一步并不是 addApplicationListener 的唯一入口,invokeBeanFactoryPostProcessors、registerBeanPostProcessors、onRefresh等方法,甚至 SpringApplication.prepareContext(在refresh前) 也可能会执行添加;
注2:
继承于 ApplicationListener 的监听器注册原理:bean 执行 initializeBean 时,Spring 的后置处理器 ApplicationListenerDetector 将对这个 Bean 执行 addApplicationListener。
附1:
ApplicationListenerDetector 属于 Spring 提供的内置后置处理器,prepareBeanFactory时{refresh的一个步骤}将 ApplicationListenerDetector 添加到 beanPostProcessors 后置处理器队列中{org.springframework.beans.factory.support.AbstractBeanFactory#beanPostProcessors}; ApplicationListenerDetector 的顶层接口是 BeanPostProcessor,BeanPostProcessor主要提供了两个抽象方法:postProcessBeforeInitialization、postProcessAfterInitialization,这两个方法分别在 initializeBean 调用 invokeInitMethods{org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods}前后调用,以实现对 Bean 初始化时的一些特殊处理。
附2:
结合附1,ApplicationContextAware 对应的 BeanProcessor 是 ApplicationContextAwareProcessor,包括其他一些也是需要获取容器上下文的接口,如 ApplicationEventPublisherAware、EnvironmentAware等。具体可以查看 org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization。 ApplicationContextAwareProcessor 也是在 prepareBeanFactory 时加入的后置处理器队列。
继承ApplicationListener注册监听器时序图
initializeBean
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean); // 一些aware接口的处理,如BeanNameAware
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); // 初始化前处理(后置处理器)
}
try {
invokeInitMethods(beanName, wrappedBean, mbd); // 初始化init
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); // 初始化后处理(后置处理器)
}
return wrappedBean;
}
applyBeanPostProcessorsBeforeInitialization
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
postProcessBeforeInitialization
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
postProcessAfterInitialization
// org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
addApplicationListener
// org.springframework.context.support.AbstractApplicationContext#addApplicationListener
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener); // 注册到广播器中
}
this.applicationListeners.add(listener);
}
2.3 事件广播、处理源码分析
- 事件发布 applicationContext.publishEvent(applicationEvent)
/** org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) */
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// do sth...
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
// 广播器广播给事件监听器
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
// if have parent, continue to publish...
}
/** org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType) */
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor(); //事件处理的线程池(没有设置异步处理的线程池则由发布的线程处理)
Iterator var5 = this.getApplicationListeners(event, type).iterator(); //根据事件类型寻找已经注册的感兴趣的监听器
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> { //交由监听器处理事件(异步)
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
- 监听器处理
/** org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener */
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event); //监听器继承ApplicationListener重写的处理方法
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, var6);
}
}
}
2.4 @EventListener 注册实现分析
@EventListener 加在 Spring 管理的 bean 的方法上,可以将该方法当成事件处理,其实现由 EventListenerMethodProcessor 支持。
(1)EventListenerMethodProcessor 注入
/**
路径扫描时调用,AnnotationConfigUtils 将 Spring 的一些底层处理类的 BeanDefinition 加入容器中
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// ...
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));
}
// ...
}
(2)EventListenerMethodProcessor 调用
调用链路:AbstractApplicationContext.refresh() -> finishBeanFactoryInitialization(…) -> ConfigurableListableBeanFactory.preInstantiateSingletons()
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// ...
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
// EventListenerMethodProcessor实现了SmartInitializingSingleton 接口
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
(3)EventListenerMethodProcessor 实现
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
// afterSingletonsInstantiated() 调用 processBean
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// 查找类上声明了 @EventListener 的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
// ...
else {
// ...
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 适配器模式做适配(注意是适配器模式,这里并没有做成代理的方式)
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 注册监听器
context.addApplicationListener(applicationListener);
break;
}
}
}
//...
}
}
}
}
注:监听器排序可以看 AnnotationAwareOrderComparator
2.5 异步处理
方式一:设置taskExecutor
SimpleApplicationEventMulticaster 没有初始化 taskExecutor,可以通过自定义 bean 和传入线程池作为属性参数的方式,创建一个带线程池的ApplicationEventMulticaster。
/** 类似于以下定义 */
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// executor properties...
return taskExecutor;
}
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticaster(ConfigurableListableBeanFactory beanFactory,
ThreadPoolTaskExecutor taskExecutor) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(beanFactory);
multicaster.setTaskExecutor(taskExecutor);
return multicaster;
}
方式二:@Async
由 AsyncAnnotationBeanPostProcessor 进行后置处理,利用代理机制和异步线程完成特定方法的异步任务处理
(1)处理器注入
// Spring提供的bean,将 AsyncAnnotationBeanPostProcessor 注入容器中
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor(); // 异步后置处理器
bpp.configure(this.executor, this.exceptionHandler); // 线程和异常处理由AbstractAsyncConfiguration注入
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
return bpp;
}
}
(2)处理器注册
// 入口是 org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
final class PostProcessorRegistrationDelegate {
// 根据类型从容器中取出处理器,经过排序等一些处理后,添加进处理器队列
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// ...
for (String ppName : postProcessorNames) {
// ...
}
// ...
}
}
(3)处理器的处理逻辑
/** AsyncAnnotationBeanPostProcessor的父类 */
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 没有通知,或者是AOP的基础设施类,那么不进行代理
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
// 对已经被代理的类,不再生成代理,只是将通知添加到代理类的逻辑中
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
// 判断需要对哪些Bean进行来代理,通过创建代理去处理
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
}
// 异步处理,advisor调用builderAdvice时,创建一个AnnotationAsyncExecutionInterceptor跟advisor绑定,线程提交任务在AnnotationAsyncExecutionInterceptor的父类中
附(SpringBoot开启异步)
(1)SpringBoot启用@EnableAsync
@SpringBootApplication(exclude = xxx.class)
@EnableAsync(proxyTargetClass = true) //启用异步,true使用cglib(默认false使用JDK)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
(2)@EnableAsync开启异步实现
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class) // 了解@Import的3种加载方式
public @interface EnableAsync {
//...
}
(3)AsyncConfigurationSelector选择异步方式
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
// ...
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) { //父类的selectImports会将ProxyAsyncConfiguration放入IOC加载的队列
switch (adviceMode) {
case PROXY: // @EnableAsync 配置默认值,默认使用SpringAOP代理
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}