2017年8月10日---阶段性工作总结(事件驱动)

在实际生产开发中,我们经常会遇到业务逻辑的嵌套,比如说在支付场景中:

1.用户在我们商城购买商品以后,进行支付操作

2.用户支付完以后,我给他发一条短信告诉买家他支付成功了

3.我告诉卖家让他发货,因为买家支付成功了


在这个场景中,我可以这样写代码,通过最初级的方式:

@Service
@Transactional
public class PayService {

    @Resource
    private Msg msgService;
    @Resource
    private Send sendService;
    @Resource
    private TFlightMapper tFlightMapper;

    public void pay(int user, String fcode) {
        TFlight flight = new TFlight();
        flight.setFcode(fcode);
        flight.setOrdertime(new Date());
        flight.setUser(user);
        int insert = tFlightMapper.insert(flight);
        if (insert > 0) {
            System.out.println("用户支付成功了~");
            TMsg msg = new TMsg();
            msg.setContent("订单号为:" + fcode);
            msg.setCreatetime(new Date());
            msg.setPhone("15577882500");
            msg.setUser(user);
            msgService.msg(msg);
            Email email = new Email("系统", String.valueOf(user), "订单支付已成功", "请您尽快发货:" + fcode);
            sendService.sendMail(email);
        }
    }
}

@Service
@Transactional
public class Msg {

    @Resource
    private TMsgMapper tMsgMapper;

    public void msg(TMsg msg) {

        int insert = tMsgMapper.insert(msg);
        if (insert > 0) {
            System.out.println("给买家发一条短信提醒!!!");
        }
    }
}

@Service
@Transactional
public class Send {

    public void sendMail(Email email) {
        try {
            FileCopyUtils.copy(SerializationUtils.serialize(email), new File("e:/temp/" + email.getTitle() + ".txt"));
        } catch (IOException e) {
            throw new RuntimeException("io异常,异常信息为:" + e.getMessage());
        }
    }
}

通知卖家发货我是以邮件的方式,因为我电脑上并没有e盘
所以肯定抛出异常,我对异常进行转换。然后输出如下:


数据库中并没有插入一条数据,有些人肯定认为这不挺好嘛,我没通知成功卖家发货,
我数据库里也没存进去数据,我短信库里也没插入短信发送记录。
但是实际生产中不是这样的,用户是在银行的系统完成支付的,这相当于钱从用户账户到你账户了,你在本地表里没给用户插入记录。
而且没插入短信发送记录不代表用户没收到短信。。。这样一搞由于耦合的存在,你这就都乱了

于是我们想到了mq,想到了redis的list队列,想到了分布式,想到了一大堆高大尚的技术。
但是今天我们在这里都不用,我一直认为技术不是用来炫耀的。用最简单的技术实现最复杂的业务场景是我一直追求的目标。
我们只用spring的事件驱动去完成一个异步的处理,当然他处理能力是有限的,比前面的高大尚的技术还是有很大差距的。
于是我对类进行改造
@Service
@Transactional
public class PayService implements ApplicationContextAware {
    //ApplicationContextAware这个接口很特殊,实现这个接口就一定要重写
    //setApplicationContext这个方法,然后spring就会自动的把applicationContext
    //这个对象注入到这个方法的入参,别告诉我你不知道applicationContext是啥
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    @Resource
    private TFlightMapper tFlightMapper;

    public void pay(int user, String fcode) {
        System.out.println("用户支付开始~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

        TFlight flight = new TFlight();
        flight.setFcode(fcode);
        flight.setOrdertime(new Date());
        flight.setUser(user);
        int insert = tFlightMapper.insert(flight);

        applicationContext.publishEvent(new PayEvent(this, fcode, user));

        System.out.println("用户支付结束~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

    }
}
加入了事件源和监听器
public class PayEvent 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 PayEvent(Object source, String fcode, int user) {
        super(source);
        this.fcode = fcode;
        this.user = user;
    }
}

@Service
public class MsgHandler implements ApplicationListener
      
      
       
        {
    //PayEvent是这个监听器监听的事件

    @Resource
    private Msg msgService;

    @Override
    public void onApplicationEvent(PayEvent payEvent) {
        //监听到事件后做如下操作
        System.out.println("开始发消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        TMsg msg = new TMsg();
        msg.setContent("订单号为:" + payEvent.getFcode());
        msg.setCreatetime(new Date());
        msg.setPhone("12222220000");
        msg.setUser(payEvent.getUser());
        msgService.msg(msg);
        System.out.println("消息发送完成~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

    }
}
      
      

@Service
public class MailHandler implements ApplicationListener
       
       
        
         {
    @Resource
    private Send sendService;

    @Override
    public void onApplicationEvent(PayEvent payEvent) {
        System.out.println("开始发邮件~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Email email = new Email("系统", String.valueOf(payEvent.getUser()), "订单支付已成功", "请您尽快发货:" + payEvent.getFcode());
        sendService.sendMail(email);
        System.out.println("邮件发送成功~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    }
}
       
       


注意我下面这个啊,用的是一个spring自带的工具类,把对象转换成byte数组的,带缓存,对象不大的时候用这个工具类转就可以
对象大的话转json或者怎么着的再根据情况





然后我就很happy了,事件驱动了,解耦了,通过事件去通知监听者,由监听者去执行发短信和发油价操作了。
太开心了,于是我运行了一下代码,按着想法应该是支付数据插入成功,短信数据插入成功,然后邮件发送失败
但是现实却还是跟刚才一样,为什么呢?看一下控制台输出


开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
反复执行多次都是这样,说明,这个事件的机制根本就是在一个线程里面。。。。

    
      
      
    
      
      
        
       
       
        
       
       
    
      
      


    
      
      
        
       
       
        
       
       
        
       
       
        
       
       
    
      
      

感觉这个类,为每一个监听器开了一个线程应该是。
SimpleApplicationEventMulticaster就这个类。
 
    
加上以后再运行看到了想要的效果,好了不早了,先说到这里吧
最后温馨提示一下,测试的时候,让主线程sleep一会儿,别测试线程没结束呢主线程先完了。
 
    
 
    
 
   









开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值