事件驱动

来源:互联网 发布:sql server 触发器 编辑:程序博客网 时间:2024/05/23 23:25

事件驱动模型

事件驱动模型要素(what)

  • 事件
  • 事件源(生产者)
  • 注册中心(事件通道)
  • 侦听器(接受者)

事件驱动模型示意图
这里写图片描述

观察者模式

观察者设计模式涉及到两种角色:主题(Subject )和观察者(Observer )
这里写图片描述

事件驱动编程应用场景

  • js页面开发
  • Zookeeper开发
  • GUI开发(awt/swing)
  • Spring开发

事件驱动编程优点

  • 无耦合的关联:事件发布者和事件订阅者预先无需知道彼此的存在。
  • 异步消息传递:业务逻辑可以随事件同时发生。
  • 多对多的交互:一个或多个事件会影响一个或多个订阅者。
  • 基于事件的控制流程:当应用程序响应发生的事件时,应用程序流程非常自然。

Java事件编程技术方案

  • Java 提供的观察者抽象
    • java.util.Observable
    • java.util.Observer
  • Java 提供的事件驱动模型
    • java.util.EventListener
  • spring 事件驱动模型
  • 分布式事件驱动模型
    • 队列(jms)
    • 发布/订阅(jms、zookeeper)

Spring 事件驱动模型要素

事件驱动模型要素

  • 事件:org.springframework.context.ApplicationEvent
  • 事件源(生产者): applicationContext.publishEvent(event)
  • 侦听器(接受者): org.springframework.context.ApplicationListener
  • 注册中心(事件通道): org.springframework.context.event.SimpleApplicationEventMulticaster

案例

航班案例
请求预定航班 –> 写入航班表 –> 发送提醒短信 –> 发送提醒邮件 –> 预定航班结束
写入航班表是最重要的业务 如果和后面两个次要的业务耦合在一次 那么短信服务出错和邮件服务出错都会使得事务回滚 航班定制失败 这是不可取的

改进
这里写图片描述

代码

事件(订阅航班)

import org.springframework.context.ApplicationEvent;public class FlightOrderEvent extends ApplicationEvent {    private String fcode;    private int user;    public String getFcode() {        return fcode;    }    public void setFcode(String fcode) {        this.fcode = fcode;    }    public int getUser() {        return user;    }    public void setUser(int user) {        this.user = user;    }    public FlightOrderEvent(Object source, String fcode, int user) {        super(source);        this.fcode = fcode;        this.user = user;    }}

侦听器(接受者)

import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Service;import com.dongnao.event.entity.Email;import com.dongnao.event.service.EmailService;@Servicepublic class FilghtOrderEmailHandler implements ApplicationListener<FlightOrderEvent> {    @Resource    private EmailService es;    private static final Logger logger = LoggerFactory.getLogger(FilghtOrderEmailHandler.class);    @Override    public void onApplicationEvent(FlightOrderEvent event) {        // 调用邮件服务        logger.info("===================捕获预订航线信息,email开始处理==================");        Email email = new Email("系统", String.valueOf(event.getUser()), "预定航班成功", "您预订航班成功,航班号:"+event.getFcode());        es.sendMail(email);        logger.info("===================捕获预订航线信息,email已处理==================");    }}
import java.util.Date;import javax.annotation.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Service;import com.dongnao.event.entity.TMsg;import com.dongnao.event.service.MsgService;@Servicepublic class FilghtOrderMsgHandler implements ApplicationListener<FlightOrderEvent> {    @Resource    private MsgService ms;    private static final Logger logger = LoggerFactory.getLogger(FilghtOrderMsgHandler.class);    @Override    public void onApplicationEvent(FlightOrderEvent event) {        logger.info("===================捕获预订航线信息,msg开始处理==================");        //写入短信表        TMsg msg = new TMsg();        msg.setContent("您预订航班成功,航班号:"+event.getFcode());        msg.setCreatetime(new Date());        msg.setPhone("15577882500");        msg.setUser(event.getUser());        ms.addMsg(msg);        logger.info("===================捕获预订航线信息,msg已处理==================");    }}

事件源(生产者)

import java.util.Date;import javax.annotation.Resource;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import com.dongnao.event.entity.TFlight;import com.dongnao.event.event.FlightOrderEvent;import com.dongnao.event.mapper.TFlightMapper;import com.dongnao.event.service.FlightService;@Servicepublic class FlightServiceImpl implements FlightService,ApplicationContextAware {    @Resource    private TFlightMapper mapper;    private ApplicationContext applicationContext;    @Transactional    @Override    public void orderFlight(int user, String fcode) {        //写入航班表        TFlight flight = new TFlight();        flight.setFcode(fcode);        flight.setOrdertime(new Date());        flight.setUser(user);        mapper.insert(flight);        applicationContext.publishEvent(new FlightOrderEvent(this, fcode, user));    }    @Override    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext=applicationContext;    }}

运行后发先如果邮件服务或者短信服务抛出异常 那么事物依然会回滚 原因是上面代码只做到了代码解耦并没有做到线程解耦 需在applicationContext.xml中配置如下:

<!-- 异步事件处理 --><bean id="applicationEventMulticaster"    class="org.springframework.context.event.SimpleApplicationEventMulticaster">    <!-- 注入任务执行器 这样就实现了异步调用(缺点是全局的,要么全部异步,要么全部同步(删除这个属性即是同步)) -->    <property name="taskExecutor" ref="coreTaskExecutor" /></bean><bean id="coreTaskExecutor"    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">    <property name="corePoolSize" value="10" />    <property name="maxPoolSize" value="20" />    <property name="queueCapacity" value="25" />    <property name="threadNamePrefix" value="dongnao-CoreTaskExecutor" /></bean>
原创粉丝点击