在实际生产开发中,我们经常会遇到业务逻辑的嵌套,比如说在支付场景中:
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());
}
}
}
所以肯定抛出异常,我对异常进行转换。然后输出如下:
数据库中并没有插入一条数据,有些人肯定认为这不挺好嘛,我没通知成功卖家发货,
我数据库里也没存进去数据,我短信库里也没插入短信发送记录。
但是实际生产中不是这样的,用户是在银行的系统完成支付的,这相当于钱从用户账户到你账户了,你在本地表里没给用户插入记录。
而且没插入短信发送记录不代表用户没收到短信。。。这样一搞由于耦合的存在,你这就都乱了
于是我们想到了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或者怎么着的再根据情况
太开心了,于是我运行了一下代码,按着想法应该是支付数据插入成功,短信数据插入成功,然后邮件发送失败
但是现实却还是跟刚才一样,为什么呢?看一下控制台输出
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。
反复执行多次都是这样,说明,这个事件的机制根本就是在一个线程里面。。。。
感觉这个类,为每一个监听器开了一个线程应该是。
SimpleApplicationEventMulticaster就这个类。
加上以后再运行看到了想要的效果,好了不早了,先说到这里吧
最后温馨提示一下,测试的时候,让主线程sleep一会儿,别测试线程没结束呢主线程先完了。
开始了,开始了,抛异常了,没结束。
开始了,开始了,抛异常了,没结束。