業務背景
實際開發中,經常會碰到需要A服務調用B服務,B服務接收到請求傳回調用成功,實際處理需要異步,當異步處理完成之後,再通知A,如下圖:

我們希望的提供的接口與回調的方式是統一的,這樣
B
就能實作與業務解耦,業務有增加,
B
服務不需要做任何變更即可支撐。
B
怎麼實作
1
步驟是同步流程,我們可以有很多方式對接B。在java微服務中,我們可以通過http的請求,可以通過mq的方式,也可以通過dubbo(rpc)。
2
步驟在java微服務中,也可以通過上述3種方式來操作,可以與
3
方式相同,也可以不同。
1
基于dubbo方案
對應标題,基于dubbo的方案,來實作樣例
有接觸dubbo的同學都知道,dubbo是通過接口實作的方式提供服務的,那麼就有可能出現同一個接口有多個實作,provider就有很多同一個接口實作的服務,這個時候就需要有唯一辨別來區分提供的服務. consumer通過唯一辨別來指定調用具體的服務。
- 通常我們可以通過以下幾個方式來區分
- address:注冊中心位址
- group: dubbo服務分組
- version: dubbo服務版本
以下為基于dubbo具體的實作方案,預設為同一個注冊中心,使用不同的group來區分
項目結構
基于spring boot 2.3.0 + dubbo 2.7.7 + zookeeper的實作
主要的maven依賴:
1. common
還有一個很重要的需要配置dubboFilter
檔案路徑: resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter
檔案内容: dubboFacadeFilter=com.github.dubbo.DubboFacadeFilter
2. service-A
A1 A2 是一模一樣的,隻是spring.application.id 配置不同,辨別為不同的服務
為了友善測試,建立為一個spring boot web項目
3.service_B
也建立為一個spring boot web項目,提供異步延遲動态回調的功能
// 動态調用CallbackInvoker
~~~
@Component
public class CallbackInvoker implements ApplicationContextAware {
private static Map> referenceConfigMap = new ConcurrentHashMap<>();
private static Map registryConfigMap = new ConcurrentHashMap<>();
private ApplicationContext applicationContext;
/**
* 擷取注冊中心位址
*
* @param group
* @return
*/
private RegistryConfig getRegistry(String group) {
RegistryConfig registryConfig = registryConfigMap.get(group);
if (null == registryConfig) {
registryConfig = new RegistryConfig();
RegistryConfig bean = applicationContext.getBean(RegistryConfig.class);
registryConfig.setAddress(bean.getAddress());
registryConfig.setProtocol(bean.getProtocol());
registryConfigMap.put(group, registryConfig);
}
return registryConfig;
}
/**
* 擷取服務的代理對象
* @param applicationName
* @param group
* @return
*/
private ReferenceBean getReferenceConfig(String applicationName, String group) {
ReferenceBean referenceBean = referenceConfigMap.get(applicationName);
if (null == referenceBean) {
referenceBean = new ReferenceBean<>();
referenceBean.setRegistry(getRegistry(group));
referenceBean.setInterface(CallbackFacade.class);
referenceBean.setGroup(group);
referenceConfigMap.put(applicationName, referenceBean);
}
return referenceBean;
}
public void invoke(CallbackDTO callbackDTO) {
ReferenceBean referenceConfig = getReferenceConfig(callbackDTO.getApplicationName(), callbackDTO.getGroup());
if (null != referenceConfig) {
CallbackFacade callback = referenceConfig.get();
if (callback != null) {
callback.invoke(callbackDTO);
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
測試結果
總結
上面回調實作方案是基于dubbo的方式:
- 在spring cloud中也可以基于http的方式,通過服務名的方式區分。
- 也可以mq的方式通過發送不同的隊列,對應的服務進行消費。
方式有很多種,主要目的是為了讓接入方,不需要編寫多餘的代碼,完全解耦的方式實作。