前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Spring Event解耦业务开发

使用Spring Event解耦业务开发

作者头像
itliusir
发布2018-10-08 11:00:25
1K0
发布2018-10-08 11:00:25
举报
文章被收录于专栏:刘君君

摘要: 使用Spring Event解耦业务开发

正文:

使用Spring Event解耦业务开发

事件驱动

事件驱动模型通常被理解为观察者模式或者发布-订阅模型

Spring 事件是观察者模式的一种体现,对象间的一对多关系,被观察者发出信号时候会通知监听该事件的观察者;而发布-订阅模型往往需要一个调度中心,如消息队列等

观察者模式
观察者模式

业务场景

  • 用户注册
  • 发短信/确认邮件
  • 送新人优惠券
  • 送抽奖
  • ….

伪代码

主流程

代码语言:javascript
复制
//注册
userMapper.saveUser(user);
//发确认邮件
sendEmail(String email);
//发短信
sendMessage(String mobile);
//送优惠券
sendCoupon(String userId);
//送抽奖机会
sendLottery(String userId);
//各种活动...
send...();

尽管我们方法抽象的很好,但是当这种事件(注册后续操作)越来越多时,主方法就会显得很乱,并且随着业务需求的变化,这个维护起来也很麻烦

改进版

主流程

代码语言:javascript
复制
//注册
userMapper.saveUser(user);
//发送注册成功事件
publisher.publishEvent(new UserRegisterEvent(user));

注册事件

代码语言:javascript
复制
class UserRegisterEvent extends ApplicationEvent {
    private static final long serialVersionUID = -4829855648590354032L;
    
    public UserRegisterEvent(User user) {
        super(user);
    }
    
    public User getUser() {
        return (User) source;
    }
}

不同监听

代码语言:javascript
复制
//发短信监听
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)

代码语言:javascript
复制
protected void publishEvent(Object event, ResolvableType eventType) {
    //如果是ApplicationEvent类型对象
    if (event instanceof ApplicationEvent类型对象) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        //否则就new一个PayloadApplicationEvent
        applicationEvent = new PayloadApplicationEvent<Object>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        //实际执行是委托给ApplicationEventMulticaster
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
}
同步or 异步

org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

代码语言:javascript
复制
@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

代码语言:javascript
复制
@Override
public void refresh() throws BeansException, IllegalStateException {
    ...
    initApplicationEventMulticaster();
    ...
}

org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster

代码语言:javascript
复制
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        //手动实现了名称为applicationEventMulticaster的bean
    }
    else {
    	//否则就默认自定义一个名称为SimpleApplicationEventMulticaster的监听器容器
    }
}

Demo

Spring-Event-Demo

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正文:
  • 使用Spring Event解耦业务开发
    • 事件驱动
      • 业务场景
        • 伪代码
          • 改进版
            • 同步 OR 异步
              • 同步(default)
              • 异步
            • Spring Event 实现细节
              • 同步or 异步
              • 初始化
            • Demo
            相关产品与服务
            短信
            腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档