【面向接口編程(IOP)典型場(chǎng)景】底層組件如何實(shí)現(xiàn)回調(diào)通知上層應(yīng)用系統(tǒng)?
本文介紹了在賬務(wù)插件開發(fā)中,如何通過(guò)“面向接口編程”實(shí)現(xiàn)異步轉(zhuǎn)賬完成后的回調(diào)通知機(jī)制。通過(guò)定義回調(diào)接口
TransferCallback,賬務(wù)組件在異步操作完成后可通知上層應(yīng)用進(jìn)行后續(xù)業(yè)務(wù)處理。文章提供了純 Java 和 Spring 兩種實(shí)現(xiàn)方式的代碼示例,展示了接口在插件化架構(gòu)中的重要作用,體現(xiàn)了面向接口編程在解耦與擴(kuò)展方面的優(yōu)勢(shì)。
我們?cè)陂_發(fā)一個(gè)賬務(wù)插件(sby-plugin-accounting),將賬戶的充、轉(zhuǎn)、提等記賬功能進(jìn)行封裝,實(shí)現(xiàn)復(fù)用。
其中,針對(duì)賬戶的轉(zhuǎn)賬操作,為提高程序性能,我們使用“同步+異步”的處理方式:轉(zhuǎn)出賬戶的扣款在工作線程中執(zhí)行,而轉(zhuǎn)入賬戶的入賬則采用異步的方式。
那么,現(xiàn)在問(wèn)題來(lái)了,當(dāng)異步轉(zhuǎn)賬完成后,如何通知上層應(yīng)用層?
沒(méi)錯(cuò),達(dá)芬奇密碼是:面向接口編程(Interface-Oriented Programming, IOP)。通過(guò)接口定義插件契約,這是在插件化架構(gòu)中典型的解決方案。————異步轉(zhuǎn)賬完成后,依賴回調(diào)接口。上層應(yīng)用系統(tǒng)如果需要關(guān)注異步轉(zhuǎn)賬完成的結(jié)果,則實(shí)現(xiàn)回調(diào)接口,進(jìn)行特定的業(yè)務(wù)處理。
下面我們列舉關(guān)鍵代碼,來(lái)說(shuō)明如何基于OOP的IOP思想,通過(guò)回調(diào)接口實(shí)現(xiàn)記賬完成的回調(diào)通知。下圖程序結(jié)構(gòu)是個(gè)demo,其中,子包 biz代表上層應(yīng)用系統(tǒng)的業(yè)務(wù)邏輯,component 代表底層賬務(wù)組件;主包 componentdemo、componentdemospring代表純java版、spring版這兩種實(shí)現(xiàn)方式。

??純java版
1. 插件層
●插件中的回調(diào)接口TransferCallback
TransferCallback是一個(gè)interface類,定義了一個(gè)方法onTransferSuccess,這是該插件與上層應(yīng)用系統(tǒng)建立邏輯關(guān)系的紐帶。插件中的異步轉(zhuǎn)賬調(diào)用這個(gè)interface,上層應(yīng)用系統(tǒng)按需實(shí)現(xiàn)這個(gè)interface。
package jstudy.componentdemo.component;
public interface TransferCallback {
void onTransferSuccess(String transferOrderNo);
}
●插件中的轉(zhuǎn)賬服務(wù)類AccountTransferService
下面AccountTransferService是賬務(wù)轉(zhuǎn)賬服務(wù)類(記賬邏輯均為示意代碼)。其中,
- 定義了
TransferCallback字段,并對(duì)外暴露了setter操作; - 在
accountingForTos方法中依賴了這個(gè)字段的實(shí)例,達(dá)到轉(zhuǎn)賬完成后進(jìn)行回調(diào)通知的目的。
package jstudy.componentdemo.component;
// 轉(zhuǎn)賬記賬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("轉(zhuǎn)賬記賬開始");
AccountingRequest accountingRequest = new AccountingRequest(accountTransfer.getTransferOrderNo(), accountTransfer.getFrom(), accountTransfer.getTransferAmount(), true);
accountingService.accounting(accountingRequest);
// 通過(guò)異步為轉(zhuǎn)賬的收款方入賬
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("上層應(yīng)用是否實(shí)現(xiàn)了轉(zhuǎn)賬回調(diào):{}", isImplementTransferCallback);
if (isImplementTransferCallback) {
transferCallback.onTransferSuccess(accountTransfer.getTransferOrderNo());
}
}
}
2. 上層應(yīng)用層
下面TransferOrderService是應(yīng)用層的 轉(zhuǎn)賬單service 類。該類同時(shí)實(shí)現(xiàn)了TransferCallback接口。
關(guān)鍵的控制在它的構(gòu)造器中,決定是否要開啟轉(zhuǎn)賬完成通知。
// 業(yè)務(wù)轉(zhuǎn)賬單service
@Slf4j
public class TransferOrderService implements TransferCallback {
private AccountTransferService accountTransferService;
public TransferOrderService() {
accountTransferService = new AccountTransferService();
// accountTransferService.setTransferCallback(this);//是否開啟轉(zhuǎn)賬完成通知
}
public void transfer() {
log.info("轉(zhuǎn)賬單記賬");
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("=========當(dāng)前是在應(yīng)用層,進(jìn)行轉(zhuǎn)賬完成后的業(yè)務(wù)處理,轉(zhuǎn)賬單號(hào)={}", transferOrderNo);
log.info("=========已向收款人發(fā)送到賬通知短消息");
}
}
程序運(yùn)行結(jié)果
- 開啟了轉(zhuǎn)賬完成回調(diào)
08:58:49.927 [j.c.biz.TransferOrderService] - 轉(zhuǎn)賬單記賬
08:58:49.935 [j.c.component.AccountTransferService] - 轉(zhuǎn)賬記賬開始
08:58:49.938 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=A, amount=50.00
08:58:49.949 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=B, amount=-10.00
08:58:49.949 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=C, amount=-40.00
08:58:49.949 [j.c.component.AccountTransferService] - 上層應(yīng)用是否實(shí)現(xiàn)了轉(zhuǎn)賬回調(diào):true
08:58:49.949 [j.c.biz.TransferOrderService] - =========當(dāng)前是在應(yīng)用層,進(jìn)行轉(zhuǎn)賬完成后的業(yè)務(wù)處理,轉(zhuǎn)賬單號(hào)=T202508000001
08:58:49.949 [j.c.biz.TransferOrderService] - =========已向收款人發(fā)送到賬通知短消息
- 未開啟轉(zhuǎn)賬完成回調(diào)
08:58:49.927 [j.c.biz.TransferOrderService] - 轉(zhuǎn)賬單記賬
08:58:49.935 [j.c.component.AccountTransferService] - 轉(zhuǎn)賬記賬開始
08:58:49.938 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=A, amount=50.00
08:58:49.949 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=B, amount=-10.00
08:58:49.949 [j.c.component.AccountingService] - AccountingService->記賬完成. 業(yè)務(wù)單號(hào)=T202508000001, accountNo=C, amount=-40.00
08:58:49.949 [j.c.component.AccountTransferService] - 上層應(yīng)用是否實(shí)現(xiàn)了轉(zhuǎn)賬回調(diào):false
??Spring版
1. 插件層
●插件中的轉(zhuǎn)賬服務(wù)類AccountTransferService
下面AccountTransferService是賬務(wù)轉(zhuǎn)賬服務(wù)類。通過(guò)@Autowired(required = false)來(lái)注入TransferCallback實(shí)例。
package jstudy.componentdemo.component;
// 轉(zhuǎn)賬記賬service
@Service
@Slf4j
public class AccountTransferService {
@Autowired
private AccountingService accountingService;
@Autowired(required = false)
private TransferCallback transferCallback;
public void accounting(AccountTransfer accountTransfer) {
...
// 通過(guò)異步為轉(zhuǎn)賬的收款方入賬
threadPool.execute(() -> {
accountingForTos(accountTransfer);
});
}
private void accountingForTos(AccountTransfer accountTransfer) {
...
if (isImplementTransferCallback) {
transferCallback.onTransferSuccess(accountTransfer.getTransferOrderNo());
}
}
}
2. 上層應(yīng)用層
下面TransferOrderService是應(yīng)用層的 轉(zhuǎn)賬單service 類。
由于該類是由 Spring 容器托管的 bean,并且實(shí)現(xiàn)了TransferCallback接口,因此,這表示開啟了轉(zhuǎn)賬完成的回調(diào)通知。
如果不開啟,則不實(shí)現(xiàn)TransferCallback接口即可。
// 業(yè)務(wù)轉(zhuǎn)賬單service
@Service
@Slf4j
public class TransferOrderService implements TransferCallback {
@Autowired
private AccountTransferService accountTransferService;
public void transfer() {
...
}
@Override
public void onTransferSuccess(String transferOrderNo) {
...
}
}
當(dāng)看到一些不好的代碼時(shí),會(huì)發(fā)現(xiàn)我還算優(yōu)秀;當(dāng)看到優(yōu)秀的代碼時(shí),也才意識(shí)到持續(xù)學(xué)習(xí)的重要!--buguge
本文來(lái)自博客園,轉(zhuǎn)載請(qǐng)注明原文鏈接:http://www.rzrgm.cn/buguge/p/19055703
posted on 2025-08-24 18:37 buguge 閱讀(66) 評(píng)論(1) 收藏 舉報(bào)
本文介紹了在賬務(wù)插件開發(fā)中,如何通過(guò)“面向接口編程”實(shí)現(xiàn)異步轉(zhuǎn)賬完成后的回調(diào)通知機(jī)制。通過(guò)定義回調(diào)接口 `TransferCallback`,賬務(wù)組件在異步操作完成后可通知上層應(yīng)用進(jìn)行后續(xù)業(yè)務(wù)處理。文章提供了純 Java 和 Spring 兩種實(shí)現(xiàn)方式的代碼示例,展示了接口在插件化架構(gòu)中的重要作用,體現(xiàn)了面向接口編程在解耦與擴(kuò)展方面的優(yōu)勢(shì)。
浙公網(wǎng)安備 33010602011771號(hào)