摘要: 使用Spring Event解耦业务开发
正文: 使用Spring Event解耦业务开发 事件驱动 事件驱动模型通常被理解为观察者模式 或者发布-订阅模型
Spring 事件是观察者模式的一种体现,对象间的一对多关系,被观察者发出信号时候会通知监听该事件的观察者;而发布-订阅模型往往需要一个调度中心,如消息队列等
业务场景
用户注册
发短信/确认邮件
送新人优惠券
送抽奖
….
伪代码 主流程
1 2 3 4 5 6 7 8 9 10 11 12 userMapper.saveUser(user); sendEmail(String email); sendMessage(String mobile); sendCoupon(String userId); sendLottery(String userId); send...();
尽管我们方法抽象的很好,但是当这种事件(注册后续操作)越来越多时,主方法就会显得很乱,并且随着业务需求的变化,这个维护起来也很麻烦
改进版 主流程
1 2 3 4 userMapper.saveUser(user); publisher.publishEvent(new UserRegisterEvent(user));
注册事件
1 2 3 4 5 6 7 8 9 10 11 class UserRegisterEvent extends ApplicationEvent { private static final long serialVersionUID = -4829855648590354032L ; public UserRegisterEvent (User user) { super (user); } public User getUser () { return (User) source; } }
不同监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MessageListener implements ApplicationListener <UserRegisterEvent > { @Override public void onApplicationEvent (UserRegisterEvent event) { sendMessage(event.getUser().getMobile()); } } class CouponListener implements ApplicationListener <UserRegisterEvent > { @Override public void onApplicationEvent (UserRegisterEvent event) { sendCoupon(event.getUser().getId()); } }
同步 OR 异步 Spring 事件既可以同步又可以异步,对于重要的业务最好采用同步方式,对于不重要的或不希望其阻塞主线程从而导致响应变慢可以采用异步方式
同步(default) 监听会加入到主线程的事务中,可以通过Order来调整bean装配的优先级来实现监听的执行顺序
异步 需要配置线程池来实现,顺序无法保证
综上所述,Spring 事件主要还是对代码层面的解耦
Spring Event 实现细节
Source: 4.2
以 publisher.publishEvent()
为入口
org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected void publishEvent (Object event, ResolvableType eventType) { if (event instanceof ApplicationEvent类型对象) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<Object>(this , event); if (eventType == null ) { eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } if (this .earlyApplicationEvents != null ) { this .earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } }
同步or 异步 org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void multicastEvent (final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null ) { executor.execute(new Runnable() { @Override public void run () { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } }
初始化 org.springframework.context.support.AbstractApplicationContext#refresh
1 2 3 4 5 6 @Override public void refresh () throws BeansException, IllegalStateException { ... initApplicationEventMulticaster(); ... }
org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
1 2 3 4 5 6 7 8 9 protected void initApplicationEventMulticaster () { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { } else { } }
Demo Spring-Event-Demo