本文介紹了在賬務插件開發中,如何通過“面向接口編程”實現異步轉賬完成後的回調通知機制。通過定義回調接口
TransferCallback,賬務組件在異步操作完成後可通知上層應用進行後續業務處理。文章提供了純 Java 和 Spring 兩種實現方式的代碼示例,展示了接口在插件化架構中的重要作用,體現了面向接口編程在解耦與擴展方面的優勢。
我們在開發一個賬務插件(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(String transferOrderNo);
}
●插件中的轉賬服務類AccountTransferService
下面AccountTransferService是賬務轉賬服務類(記賬邏輯均為示意代碼)。其中,
- 定義了
TransferCallback字段,並對外暴露了setter操作; - 在
accountingForTos方法中依賴了這個字段的實例,達到轉賬完成後進行回調通知的目的。
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(accountTransfer.getTransferOrderNo());
}
}
}
2. 上層應用層
下面TransferOrderService是應用層的 轉賬單service 類。該類同時實現了TransferCallback接口。
關鍵的控制在它的構造器中,決定是否要開啓轉賬完成通知。
// 業務轉賬單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(String transferOrderNo) {
log.info("=========當前是在應用層,進行轉賬完成後的業務處理,轉賬單號={}", transferOrderNo);
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] - =========當前是在應用層,進行轉賬完成後的業務處理,轉賬單號=T202508000001
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(accountTransfer.getTransferOrderNo());
}
}
}
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(String transferOrderNo) {
...
}
}