# asyncmdDemo
**Repository Path**: wangwendi/asyncmdDemo
## Basic Information
- **Project Name**: asyncmdDemo
- **Description**: 异步命令组件demo
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2019-07-29
- **Last Updated**: 2024-11-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# asyncmdDemo
异步命令组件demo
需要根据sql文件夹里的sql语句创建表
然后修改jdbc.properties里的数据库url和用户名密码
组件相关配置都在 spring-service.xml文件中
三个测试功能
- SmsController 接收发送短信请求异步发送
- GiveRewardController 接收赠送奖励请求 异步赠送奖励
- CouponController 定时赠送指定用户一批优惠券
- OrderCreateListener和OrderModifyListener实现mq的顺序消费 保证同一笔订单肯定先处理订单创建消息 再处理订单修改消息
com.asyncmdDemo.asyn.asynbiz 存放异步命令业务对象
com.asyncmdDemo.asyn.asyncmd 存放异步命令对象
com.asyncmdDemo.asyn.asynexecuter 存放异步命令执行器
com.asyncmdDemo.asyn.callback 执行器执行异常回调
SmsAsynCmd异步命令对象里设置里一些异步命令个性化的设置
#### 使用逻辑
新建一个异步命令对象 一个异步命令执行器 把请求传过来的数据保存到这个异步命令对象中 调用组件到一个服务 就会把对象保存到表中 并且异步的执行创建的异步命令执行器 会把异步命令对象作为入参传进去 使用者只要在异步命令执行器中把后续逻辑写好就可以 重试之类的机制组件会自动完成
## 快速使用
1、引入jar
```
com.bojiw
asyncmd-core
1.8
```
2、在spring的xml文件中 引入xml文件
```
```
3、配置AsynGroupConfig
```
```
4、创建自己业务的asynBizObject,asynCmd,asynExecuter
主要是继承AsynBizObject,AsynCmd,AbstractAsynExecuter
例子:
```
/**
* 短信业务模型
* @author wangwendi
* @version $Id: SmsBiz.java, v 0.1 2019年07月23日 下午8:58 wangwendi Exp $
*/
public class SmsBiz extends AsynBizObject {
/**
* 手机号
*/
private String mobiles;
/**
* 短信内容
*/
private String content;
public String getMobiles() {
return mobiles;
}
public void setMobiles(String mobiles) {
this.mobiles = mobiles;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
```
```
/**
* 短信异步命令
* @author wangwendi
* @version $Id: SmsAsynCmd.java, v 0.1 2019年07月23日 下午8:57 wangwendi Exp $
*/
public class SmsAsynCmd extends AsynCmd {
/**
* 必须实现 返回对应的AsynBizObject
**/
@Override
protected Class getObject() {
return SmsBiz.class;
}
}
```
```
/**
* 短信异步命令执行器 需要注入到spring容器中 加@Service注解或者xml配置bean
* @author wangwendi
* @version $Id: SmsExecuter.java, v 0.1 2019年07月23日 下午9:01 wangwendi Exp $
*/
@Service
public class SmsExecuter extends AbstractAsynExecuter {
/**
* 具体业务逻辑 调度方式有三种 异步调度(保存异步命令以后,立刻扔到线程池执行)、调度中心调度(保存异步命令以后不做任何操作 由定时任务捞取数据进行执行)、同步调度(保存异步命令以后立刻同步执行executer方法) 默认是异步调度 可以设置其他三种方式调度 设置方法看demo或者详细配置项
**/
@Override
protected void executer(SmsAsynCmd cmd) {
SmsBiz content = cmd.getContent();
System.out.println("发送短信");
System.out.println("短信手机号" + content.getMobiles());
}
}
```
5、执行源码sql目录下的asyn.sql创建表
根据前面第三步设置的asynGroupConfig.tableNum分表数量来创建对应的表数量 如上面设置的4 则创建asyn_cmd00,asyn_cmd01,asyn_cmd02,asyn_cmd03 4张表
6、使用异步命令门面服务AsynExecuterFacade 保存异步命令 可以直接用@Autowired注解注入就可以
```
@Autowired
private AsynExecuterFacade asynExecuterFacade;
//创建业务对象 创建异步命令对象 然后调用方法 就会自动执行SmsExecuter.executer方法
SmsBiz smsBiz = new SmsBiz();
smsBiz.setContent(content);
smsBiz.setMobiles(mobiles);
SmsAsynCmd asynCmd = new SmsAsynCmd();
asynCmd.setContent(smsBiz);
asynCmd.setBizId(bizId);
asynExecuterFacade.saveExecuterAsynCmd(asynCmd);
```
## 注意点
- 为了保证可靠性 当出现极端情况下 比如执行器执行成功了 修改命令状态时系统挂了 会出现重复执行的情况 所以执行器需要保证幂等
- 如果应用系统已经使用了quartz 需要版本为2.1.7以上
## 分表情况根据业务id查询保存在哪张表
调用SubTableUtil#getIndex(分表数量,bizId) 可以获取异步命令在哪张表中 方便排查问题
## 详细配置项
有两个地方可以配置 一个为全局配置项AsynGroupConfig 一个为设置个性化配置项AbstractAsynExecuter
```
```
对不同异步命令对象进行个性化对配置
```
//如果有需要对某个异步命令对象做个性化设置 可以通过注解的方式 设置调度方式为调度中心调度 设置调度频率为 4s,4s,4m
@AsynCmdConf(dispatchMode = DispatchMode.DISPATCH,executerFrequency = "4s,4s")
public class SmsAsynCmd extends AsynCmd {
public static final String name = "sms";
/**
* 需要返回业务对象类 组件里要用
* @return
*/
@Override
protected Class getObject() {
return SmsBiz.class;
}
}
```
设置异步命令执行器的排序值 数值越大 越早执行 默认100
```
//设置排序值为90
@AsynExecuterConf(sort = 90)
@Service
public class SmsExecuter extends AbstractAsynExecuter {
```
## 模型
asynCmdDB(异步命令对象)
| 字段名 | 描述 |
| :------------ | :------------ |
| cmdId | 单表唯一id由表自增 |
| cmdType | 异步命令类型 异步命令对象类的名称 |
| bizId | 业务id 全局唯一 根据这个ID做hash然后取余获取分表位 计算逻辑和hashmap计算下标为相同 |
| content | 业务上下文 业务对象AsynBizObject的json数据 |
| executeNum | 异步命令对象执行次数 重试一次加1 |
| nextTime | 下一次执行时间 根据设置的重试频率来计算 |
| status | 状态 分为"INIT","初始化" "EXECUTE","执行中" "SUCCESS","成功" "ERROR","失败" |
| createHostName | 执行插入异步命令服务器的主机名 方便排查问 |
| createIp | 执行插入异步命令服务器的ip地址 方便排查问题 |
| updateHostName | 更新异步命令服务器的主机名 方便排查问题 |
| updateIp | 更新异步命令服务器的ip地址 方便排查问题 |
| createName | 创建异步命令的人 默认system |
| successExecuters | 执行成功的异步命令执行器类名 如果一个异步命令对象对应多个异步命令执行器 通过这个可以看有成功执行的异步命令对象 |
| env | 所在环境 |
| exception | 异步命令执行时的异常信息 |
| rely_biz_id | 依赖的异步命令业务id |
| gmtCreate | 创建时间 |
| gmtModify | 修改时间 |
AsynCmdHistoryDO异步命令历史模型 字段和内容和异步命令对象模型一样 只有创建时间和更新时间不同
## 三种调度方式
DispatchMode
异步调度

调度中心调度

同步调度
