我们在开发一个账务插件(sby-plugin-accounting),将账户的充、转、提等记账功能进行封装,实现复用。
其中,为了提高程序性能,针对账户转账的记账,使用了异步处理:转出账户的扣款在工作线程中执行,而转入账户的入账则采用异步的方式。
那么,现在问题来了,当异步转账完成后,如何通知上层应用层?
没错,达芬奇密码是:面向接口编程(Interface-Oriented Programming, IOP)。通过接口定义插件契约,这是在插件化架构中典型的解决方案。————异步转账完成后,依赖回调接口。上层应用系统如果需要关注异步转账完成的结果,则实现回调接口,进行特定的业务处理。
下面我们列举关键代码,来说明如何基于OOP的IOP思想,通过回调接口实现记账完成的回调通知。下图程序结构是个demo,其中,子包 biz
代表上层应用系统的业务逻辑,component
代表底层账务组件;主包 componentdemo
、componentdemospring
代表纯java版、spring版这两种实现方式。
🍀纯java版
1. 插件层
●插件中的回调接口TransferCallback
TransferCallback
是一个interface
类,定义了一个方法onTransferSuccess
,这是该插件与上层应用系统建立逻辑关系的纽带。插件中的异步转账调用这个interface
,上层应用系统按需实现这个interface
。
package jstudy.componentdemo.component;
public interface TransferCallback {
void onTransferSuccess();
}
●插件中的转账服务类AccountTransferService
下面AccountTransferService
是账务转账服务类(记账逻辑均为示意代码)。其中,
- 定义了
TransferCallback
字段,并对外暴露了setter操作; - 在
accountingForTos
方法中依赖了这个字段的实例,达到转账完成后进行回调通知的目的。
```java
package jstudy.componentdemo.component;
// 转账记账service
@Slf4j
public class AccountTransferService {
private AccountingService accountingService = new AccountingService();
@Setter
private TransferCallback transferCallback;
private static final Executor threadPool = ...;
public void accounting(AccountTransfer accountTransfer) {
log.info("转账记账开始");
AccountingRequest accountingRequest = new AccountingRequest(accountTransfer.getTransferOrderNo(), accountTransfer.getFrom(), accountTransfer.getTransferAmount(), true);
accountingService.accounting(accountingRequest);
// 通过异步为转账的收款方入账
threadPool.execute(() -> {
accountingForTos(accountTransfer);
});
}
private void accountingForTos(AccountTransfer accountTransfer) {
var listTo = accountTransfer.getTos();// 收款方集合
for (var entry: listTo.entrySet()) {
AccountingRequest accountingRequest = new AccountingRequest(accountTransfer.getTransferOrderNo(), entry.getKey(), entry.getValue(), false);
accountingService.accounting(accountingRequest);
}
boolean isImplementTransferCallback = transferCallback != null;
log.info("上层应用是否实现了转账回调:{}", isImplementTransferCallback);
if (isImplementTransferCallback) {
transferCallback.onTransferSuccess();
}
}
}
## 2. 上层应用层
下面`TransferOrderService`是应用层的 转账单service 类。该类同时实现了`TransferCallback`接口。
关键的控制在它的构造器中,决定是否要**开启**转账完成通知。
```java
// 业务转账单service
@Slf4j
public class TransferOrderService implements TransferCallback {
private AccountTransferService accountTransferService;
public TransferOrderService() {
accountTransferService = new AccountTransferService();
// accountTransferService.setTransferCallback(this);//是否开启转账完成通知
}
public void transfer() {
log.info("转账单记账");
AccountTransfer accountTransfer = new AccountTransfer();
accountTransfer.setTransferOrderNo("T202508000001")
.setFrom("A")
.setTransferAmount(50.00);
accountTransfer.setTos(ImmutableMap.of(
"B", 10.00,
"C", 40.00));
accountTransferService.accounting(accountTransfer);
}
@Override
public void onTransferSuccess() {
log.info("=========当前是在应用层,进行转账完成后的业务处理");
log.info("=========已向收款人发送到账通知短消息");
}
}
程序运行结果
- 开启了转账完成回调
08:58:49.927 [j.c.biz.TransferOrderService] - 转账单记账 08:58:49.935 [j.c.component.AccountTransferService] - 转账记账开始 08:58:49.938 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=A, amount=50.00 08:58:49.949 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=B, amount=-10.00 08:58:49.949 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=C, amount=-40.00 08:58:49.949 [j.c.component.AccountTransferService] - 上层应用是否实现了转账回调:true 08:58:49.949 [j.c.biz.TransferOrderService] - =========当前是在应用层,进行转账完成后的业务处理 08:58:49.949 [j.c.biz.TransferOrderService] - =========已向收款人发送到账通知短消息
- 未开启转账完成回调
08:58:49.927 [j.c.biz.TransferOrderService] - 转账单记账 08:58:49.935 [j.c.component.AccountTransferService] - 转账记账开始 08:58:49.938 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=A, amount=50.00 08:58:49.949 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=B, amount=-10.00 08:58:49.949 [j.c.component.AccountingService] - AccountingService->记账完成. 业务单号=T202508000001, accountNo=C, amount=-40.00 08:58:49.949 [j.c.component.AccountTransferService] - 上层应用是否实现了转账回调:false
🍀spring版
1. 插件层
●插件中的转账服务类AccountTransferService
下面AccountTransferService
是账务转账服务类。通过@Autowired(required = false)
来注入TransferCallback
实例。
package jstudy.componentdemo.component;
// 转账记账service
@Service
@Slf4j
public class AccountTransferService {
@Autowired
private AccountingService accountingService;
@Autowired(required = false)
private TransferCallback transferCallback;
public void accounting(AccountTransfer accountTransfer) {
...
// 通过异步为转账的收款方入账
threadPool.execute(() -> {
accountingForTos(accountTransfer);
});
}
private void accountingForTos(AccountTransfer accountTransfer) {
...
if (isImplementTransferCallback) {
transferCallback.onTransferSuccess();
}
}
}
2. 上层应用层
下面TransferOrderService
是应用层的 转账单service 类。
由于该类是由 spring 容器托管的 bean,并且实现了TransferCallback
接口,因此,这表示开启了转账完成的回调通知。
如果不开启,则不实现TransferCallback
接口即可。
// 业务转账单service
@Service
@Slf4j
public class TransferOrderService implements TransferCallback {
@Autowired
private AccountTransferService accountTransferService;
public void transfer() {
...
}
@Override
public void onTransferSuccess() {
...
}
}