spring事件驱动分析

x33g5p2x  于2021-09-19 转载在 Spring  
字(20.1k)|赞(0)|评价(0)|浏览(640)

前言

众所周知,在领域驱动设计中聚合根的设计有一个很重要的原则:

每个事务应该只更新一个聚合根。

然而,在我们的实际业务中,经常会出现涉及到多个聚合根同时更新的场景。这无疑对于系统设计提出了不小的挑战,设计一个粒度适中,又能符合业务要求的聚合根并不是一件容易的事情。领域事件为我们提供了一种非常简单的解决方案:在聚合根完成更新后产生一个新的事件并广播出去,由其他订阅该事件的订阅者完成其他聚合根的更新,这样就解除了聚合根之间的耦合。

如果是多个域之间的事件交互,可以考虑使用kafka等消息中间件实现,今天本文介绍的是spring中的事件编程,适合用在单个域中包含多个聚合根的场景。

在java中,本身就已经自带了对事件编程的支持(java.util.EventObject),早期的GUI编程中使用事件编程会比较多。而spring又对java的事件做了进一步扩充,本文会通过简单梳理事件驱动编程在spring boot中的实践,学习其思想和技巧,为我们更好的设计代码架构提供参考。

spring事件编程-实践

我们先看一下spring事件编程的简单实践。

我们用spring的事件机制,模拟实现一个简单的业务场景:

在用户完成下单动作以后,我们需要给到用户邮件通知,这里涉及邮件和订单两个模块,我们在下单动作完成后,发布事件,再由邮件模块发送邮件给用户。

入口函数

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Main {

    @Autowired
    private OrderService orderService;

    @Test
    public void placeOrder(){
        Order order = new Order();
        order.setUserName("lisi");
        order.setEmail("lisi@qq.com");
        orderService.placeOrder(order);
        log.info("下单完成");
    }
}

订单实体

@Getter
@Setter
@ToString
public class Order {
    private String userName;
    private String email;
}

订单service

我们在完成订单保存后,并没有显式调用邮件发送,而是发布了一个“订单事件”,后面交给其他感兴趣的订阅模块去做相应处理,实现了很好的解耦。发布事件借助spring的ApplicationEventPublisher完成,后面会再细说它的具体实现。

@Slf4j
@Service
public class OrderService {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void placeOrder(Order order) {
        this.saveOrder(order);
        log.info("发布下单事件成功:[{}]", order);
        publisher.publishEvent(order);
    }

    private void saveOrder(Order order) {
        log.info("保存订单");
    }
}

邮件监听器:

我们只需要在业务方法上加@EventListener注解即可实现监听。

注意:监听器需要是被spring管理的bean,@Service或者@Component等都可以

@Slf4j
@Service
public class EmailListener {
    private void sendEmail(Order order){
        //发邮件
        log.info("发送邮件");
        //throw new RuntimeException("模拟发送邮件异常");
    }

    @EventListener
    public void placeOrderNotice(Order order){
        log.info("邮件监听器收到通知[{}]", order);
        this.sendEmail(order);
    }
}

运行结果

可以看到下单后,监听器拿到了订单信息,并成功发送了邮件。

需要注意的是,这里的监听器是同步执行的,如果发送邮件出现异常,那么会导致主线程后面逻辑也走不下去,如果包含事务,那么事务也会回滚。
例如,我们模拟在邮件发送中出现异常,再看结果:

private void sendEmail(Order order){
        //发邮件
        log.info("发送邮件");
        throw new RuntimeException("模拟发送邮件异常");
}

可以看到,发送邮件抛出异常,导致日志[下单完成],也没有正常执行,此处若有事务也会回滚;
要想订阅者的逻辑不影响主线程,我们可以使用异步执行的方式,在springBoot入口类添加 @EnableAsync注解,并在监听器中添加注解 @Async 即可。

@Slf4j
@EnableAsync
@RunWith(SpringRunner.class)
@SpringBootTest
public class AsyncMain {
			......
}

@Async
@EventListener
public void placeOrderNotice1(Order order){
log.info("异步邮件监听器[1]收到通知[{}]", order);
    this.sendEmail1(order);
}

如不指定Executor,则会使用默认的applicationTaskExecutor,我们也可以自定义Executor:

@Bean
  public ThreadPoolTaskExecutor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(50);
        return executor;
  }

如果有多个订阅者,还可以通过 @Order 注解指定收到通知的顺序,数字越小优先级越高,本例我们指定两个订阅者。

@Async
    @EventListener
    @org.springframework.core.annotation.Order(1)
    public void placeOrderNotice1(Order order){
        log.info("异步邮件监听器[1]收到通知[{}]", order);
        this.sendEmail1(order);
    }
		private void sendEmail1(Order order){
        log.info("发送邮件1");
        throw new RuntimeException("异步发送邮件[1]异常");
    }

    @Async
    @EventListener
    @org.springframework.core.annotation.Order(2)
    public void placeOrderNotice2(Order order){
        log.info("异步邮件监听器[2]收到通知[{}]", order);
        this.sendEmail2(order);
    }
		private void sendEmail2(Order order){
        log.info("发送邮件2");
    }

运行结果:

可以看到这里使用了自定义的myExecutor去异步化执行监听器中的逻辑,而且异步化之后,监听器[1]执行出现异常,没有影响主线程和监听器[2]。

观察者模式和发布-订阅模式

在spring中的事件编程,其实就是我们常说的设计模式中的观察者模式的实现,也看到有人说观察者模式=发布订阅模式,其实这两者是有差别的。

在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容改变的事件后,直接接收事件并作出响应,如下:

╭─────────────╮  Fire Event  ╭──────────────╮
 │             │─────────────>│              │
 │   Subject   │              │   Observer   │
 │             │<─────────────│              │
 ╰─────────────╯  Subscribe   ╰──────────────╯

在发布订阅模式中,发布者和订阅者之间多了一个发布通道;一方面从发布者接收事件,另一方面向订阅者发布事件;订阅者需要从事件通道订阅事件,以此避免发布者和订阅者之间产生依赖关系,如下:

╭─────────────╮                 ╭───────────────╮   Fire Event   ╭──────────────╮
 │             │  Publish Event  │               │───────────────>│              │
 │  Publisher  │────────────────>│ Event Channel │                │  Subscriber  │
 │             │                 │               │<───────────────│              │
 ╰─────────────╯                 ╰───────────────╯    Subscribe   ╰──────────────╯

发布-订阅可以认为是观察者模式的一种实现。在spring中的事件编程,都是观察者模式的实现,没有涉及消息中间件,如果业务足够复杂,可以考虑引入第三方消息中间件来实现领域事件。

spring事件驱动源码分析

spring这么多年经久不衰,它的源码可谓是经典中的经典,里面的抽象和设计都是值得我们学习和研究的,下面我们就一起看一下spring是如何实现事件驱动的。

Spring事件机制涉及的重要的类主要有以下四个

  • ApplicationEvent:事件,该抽象类是所有Spring事件的父类,继承自java的EventObject。
  • ApplicationListener:事件监听器接口,继承自java的EventListener。
  • ApplicationEventMulticaster:事件管理者,管理监听器和发布事件,ApplicationContext通过委托ApplicationEventMulticaster来 发布事件
  • ApplicationEventPublisher:事件发布者,该接口封装了事件有关的公共方法,作为ApplicationContext的超级接口,也是委托 ApplicationEventMulticaster完成事件发布。

然后我们开始看具体的源码。我们从最简单的发布事件开始跟踪,可以看到,publishEvent方法的逻辑最终是在AbstractApplicationContext.java中,而AbstractApplicationContext是ApplicationEventPublisher的实现类:

publishEvent()源码跟踪:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }

        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
						//注意这里,委托给ApplicationEventMulticaster发布器去处理了
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }

        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }

    }

我们再看发布器的初始化代码initApplicationEventMulticaster:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
						//注意这里,用实现类SimpleApplicationEventMulticaster去处理发布事件
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }

    }

再看SimpleApplicationEventMulticaster中的发布事件方法multicastEvent():

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);
            }
        }

    }

再看invokeListener:

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
								//看这个
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
						//看这个
            this.doInvokeListener(listener, event);
        }

    }

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
						//实际上执行了监听器的onApplicationEvent方法
            listener.onApplicationEvent(event);
        } 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);
            }
        }

    }

总结一下上面的流程:ApplicationEventPublisher发布事件是委托给ApplicationEventMulticaster去执行的,ApplicationEventMulticaster的实现类SimpleApplicationEventMulticaster最终会调用ApplicationListener的onApplicationEvent方法。

@EventListener注解实现源码分析

那么问题来了,我们的监听器实际上只用了一个@EventListener注解,并没有onApplicationEvent方法,spring又是如何来识别的呢?

众所周知,spring容器启动时,会有一个refresh的动作(org.springframework.boot.SpringApplication/#run()),如下:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //准备变量
						this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //注意这里:刷新容器
						this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

再看refreshContext()里面的内容:

private void refreshContext(ConfigurableApplicationContext context) {
        //再看下面
				this.refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
 }
protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
				//调用了applicationContext.refresh()
        ((AbstractApplicationContext)applicationContext).refresh();
}

里面实际调用了applicationContext的refresh,applicationContext就是我们前面调用publishEvent的类,也是ApplicationEventPublisher的实现类,我们来看看AbstractApplicationContext的refresh做了什么:

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
								//初始化事件发布器
                this.initApplicationEventMulticaster();
                this.onRefresh();
								//注册事件监听器
                this.registerListeners();
								//我们要关注的和注解有关的地方
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

我们来看finishBeanFactoryInitialization()方法:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
            beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
        }

        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver((strVal) -> {
                return this.getEnvironment().resolvePlaceholders(strVal);
            });
        }

        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        String[] var3 = weaverAwareNames;
        int var4 = weaverAwareNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String weaverAwareName = var3[var5];
            this.getBean(weaverAwareName);
        }

        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
				//注意这里
        beanFactory.preInstantiateSingletons();
    }

继续跟进preInstantiateSingletons():

public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Pre-instantiating singletons in " + this);
        }

        List<String> beanNames = new ArrayList(this.beanDefinitionNames);
        Iterator var2 = beanNames.iterator();

        while(true) {
            String beanName;
            Object bean;
            do {
                while(true) {
                    RootBeanDefinition bd;
                    do {
                        do {
                            do {
                                if (!var2.hasNext()) {
                                    var2 = beanNames.iterator();

                                    while(var2.hasNext()) {
                                        beanName = (String)var2.next();
                                        Object singletonInstance = this.getSingleton(beanName);
                                        if (singletonInstance instanceof SmartInitializingSingleton) {
                                            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                            if (System.getSecurityManager() != null) {
                                                AccessController.doPrivileged(() -> {
																										//注意这里
                                                    smartSingleton.afterSingletonsInstantiated();
                                                    return null;
                                                }, this.getAccessControlContext());
                                            } else {
																								//注意这里
                                                smartSingleton.afterSingletonsInstantiated();
                                            }
                                        }
                                    }

                                    return;
                                }

                                beanName = (String)var2.next();
                                bd = this.getMergedLocalBeanDefinition(beanName);
                            } while(bd.isAbstract());
                        } while(!bd.isSingleton());
                    } while(bd.isLazyInit());

                    if (this.isFactoryBean(beanName)) {
                        bean = this.getBean("&" + beanName);
                        break;
                    }

                    this.getBean(beanName);
                }
            } while(!(bean instanceof FactoryBean));

            FactoryBean<?> factory = (FactoryBean)bean;
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                SmartFactoryBean var10000 = (SmartFactoryBean)factory;
                ((SmartFactoryBean)factory).getClass();
                isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
            } else {
                isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
            }

            if (isEagerInit) {
                this.getBean(beanName);
            }
        }
    }

再来看SmartInitializingSingleton.afterSingletonsInstantiated(),SmartInitializingSingleton这个接口有几个实现类,明显EventListenerMethodProcessor就是我们所关注的:

再看EventListenerMethodProcessor.afterSingletonsInstantiated():

public void afterSingletonsInstantiated() {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        String[] var3 = beanNames;
        int var4 = beanNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String beanName = var3[var5];
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class type = null;

                try {
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                } catch (Throwable var10) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Could not resolve target class for bean with name '" + beanName + "'", var10);
                    }
                }

                if (type != null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            Class<?> targetClass = AutoProxyUtils.determineTargetClass(beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                            if (targetClass != null) {
                                type = targetClass;
                            }
                        } catch (Throwable var11) {
                            if (this.logger.isDebugEnabled()) {
                                this.logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", var11);
                            }
                        }
                    }

                    try {
												//我们的关注点
                        this.processBean(beanName, type);
                    } catch (Throwable var9) {
                        throw new BeanInitializationException("Failed to process @EventListener annotation on bean with name '" + beanName + "'", var9);
                    }
                }
            }
        }

    }

再看processBean():

private void processBean(String beanName, Class<?> targetType) {
				//处理@EventListener注解的方法
        if (!this.nonAnnotatedClasses.contains(targetType) && AnnotationUtils.isCandidateClass(targetType, EventListener.class) && !isSpringContainerClass(targetType)) {
            Map annotatedMethods = null;

            try {
                annotatedMethods = MethodIntrospector.selectMethods(targetType, (methodx) -> {
                    return (EventListener)AnnotatedElementUtils.findMergedAnnotation(methodx, EventListener.class);
                });
            } catch (Throwable var12) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Could not resolve methods for bean with name '" + beanName + "'", var12);
                }
            }

            if (CollectionUtils.isEmpty(annotatedMethods)) {
                this.nonAnnotatedClasses.add(targetType);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
                }
            } else {
                ConfigurableApplicationContext context = this.applicationContext;
                Assert.state(context != null, "No ApplicationContext set");
                List<EventListenerFactory> factories = this.eventListenerFactories;
                Assert.state(factories != null, "EventListenerFactory List not initialized");
                Iterator var6 = annotatedMethods.keySet().iterator();

                while(true) {
                    while(var6.hasNext()) {
                        Method method = (Method)var6.next();
                        Iterator var8 = factories.iterator();

                        while(var8.hasNext()) {
                            EventListenerFactory factory = (EventListenerFactory)var8.next();
                            if (factory.supportsMethod(method)) {
                                Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
																//EventListenerFactory这里根据我们@EventListener注解的方法构建出了ApplicationListener
                                ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);
                                if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                    ((ApplicationListenerMethodAdapter)applicationListener).init(context, this.evaluator);
                                }

                                context.addApplicationListener(applicationListener);
                                break;
                            }
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods);
                    }
                    break;
                }
            }
        }

    }

我们再来看EventListenerFactory.createApplicationListener():

public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
        //这里其实是使用了适配器模式,构建了一个适配器返回
				return new ApplicationListenerMethodAdapter(beanName, type, method);
    }

可以看到ApplicationListenerMethodAdapter适配器继承自ApplicationListener

到这里,其实就已经很清晰了,在spring容器启动时applicationContext会调用refresh方法,然后一路跟踪到注解@EventListenser的处理类EventListenerMethodProcessor中的afterSingletonsInstantiated()方法,再到EventListenerMethodProcessor.processBean()中,找到了对针对注解@EventListenser的处理逻辑:
根据传入的beanName通过EventListenerFactory构建出一个ApplicationListenerMethodAdapter适配器,该适配器也是ApplicationListenser的实现,也就把我们用@EventListenser注解的方法适配成了ApplicationListenser的实现。

最后我们再看看,这个适配器是如何实现适配的。我们知道,发布事件时会调用onApplicationEvent方法,我们来看看ApplicationListenerMethodAdapter中的onApplicationEvent实现:

public void onApplicationEvent(ApplicationEvent event) {
				//看下面的具体方法
        this.processEvent(event);
}

public void processEvent(ApplicationEvent event) {
        Object[] args = this.resolveArguments(event);
        if (this.shouldHandle(event, args)) {
						//这里通过反射来执行被@EventListenser注解的方法
            Object result = this.doInvoke(args);
            if (result != null) {
                this.handleResult(result);
            } else {
                this.logger.trace("No result object given - no result to handle");
            }
        }

 }

		@Nullable
    protected Object doInvoke(Object... args) {
        Object bean = this.getTargetBean();
        ReflectionUtils.makeAccessible(this.method);

        try {
						// this.method是构造adapter时传入的变量,就是被@EventListenser注解的方法
            return this.method.invoke(bean, args);
        } catch (IllegalArgumentException var6) {
            this.assertTargetBean(this.method, bean, args);
            throw new IllegalStateException(this.getInvocationErrorMessage(bean, var6.getMessage(), args), var6);
        } catch (IllegalAccessException var7) {
            throw new IllegalStateException(this.getInvocationErrorMessage(bean, var7.getMessage(), args), var7);
        } catch (InvocationTargetException var8) {
            Throwable targetException = var8.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException)targetException;
            } else {
                String msg = this.getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
                throw new UndeclaredThrowableException(targetException, msg);
            }
        }
    }

//ApplicationListenerMethodAdapter的构造方法
public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
        this.beanName = beanName;
				//这个方法就是被@EventListenser注解的方法
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        this.targetMethod = !Proxy.isProxyClass(targetClass) ? AopUtils.getMostSpecificMethod(method, targetClass) : this.method;
        this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
        EventListener ann = (EventListener)AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
        this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
        this.condition = ann != null ? ann.condition() : null;
        this.order = resolveOrder(this.targetMethod);
}

总结下,ApplicationListenerMethodAdapter适配器构造时会传入被@EventListenser注解的方法,然后在onApplicationEvent()中通过反射,调用传入的方法,就实现了注解方式的事件发布。

结语

本文简介了spring的事件驱动编程实践,以及源码实现,希望能给大家的使用提供一些借鉴。事件驱动为我们提供了一种十分优秀的解耦的手段,可以将大量复杂的业务逻辑拆分到不同的订阅者中去处理,让我们的代码更符合SRP原则。而且,spring已经为我们在java的事件基础上提供了优秀的二次封装,推荐大家在合适的业务场景中去尝试一下。


—by eric02.li

相关文章