在复杂的业务开发的时候,对于业务的解耦有利于系统的健壮性和灵活性,Spring内部spring-context包中event包下提供了对于事件的支持。
1.简单使用
@Resource
ApplicationEventPublisher applicationEventPublisher;
// 发送事件
public void sendEvent() {
EventDTO eventDTO = new EventDTO();
applicationEventPublisher.publishEvent(eventDTO);
}
// 监听事件
@EventListener
public void listenEvent(EventDTO eventDTO) {
System.out.println( Thread.currentThread().getName()+" "+eventDTO);
}
2.流程分析
注:Multicaster为ApplicationEventMulticaster。
3.源码分析
在这整个流程中,Multicaster广播器主要负责发送事件到各个订阅的Listener方法中,整个流程的核心节点。在分析整个Event之前需要对在Spring启动时,如何注入广播器等等工作做一个简单分析。<br />Spring的启动注入流程如下:
@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);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
在以上的方法中,对于启动的过程,我们主要分析 initApplicationEventMulticaster
方法以及 registerListeners();
方法还有 finishBeanFactoryInitialization(beanFactory);
。方法一主要是注册事件广播器,方法二主要是注册监听器,方法三主要是在所有的非懒加载的Bean初始化后将含有@EventListener注解的Bean包装为ApplicationListener中,然后注入到Spring IOC容器中。
注册广播器的核心代码如下:
// 创建一个简单广播器,传入beanFactory主要用于后期获取BeanFactory中的Listener
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 将广播器单例bean注入到Spring IOC容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
注册Listener到广播器的核心代码如下:
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
// earlyApplicationEvents 是容器刚刚初始化所构建的Event链表,里面主要保存在广播器够着之前
// 需要发放的Event
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
此方法主要将容器中所有声明的ApplicationLister的Bean对象加载到广播器中,并且发送在广播器和Bean准备期间所需要发送的事件。
将容器中初始化好的Spring Bean中包含@EventListener注解的方法和Bean包裹到一个新通用的ApplicationLister子类(即ApplicationListenerMethodAdapter中),核心代码如下:
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 {
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");
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 =
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);
}
}
}
}
这里重点介绍一下ApplicationListenerMethodAdapter类,其继承自ApplicationLister实现onApplicationEvent方法,传入参数:String beanName, Class<?> targetClass, Method method(@EventListener的目标方法)。其实现如下:
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
doInvoke会利用反射的方式执行目标方法,handleResult会将目标犯法执行的结果继续当做Event发送出去。