业务背景
实际开发中,经常会碰到需要A服务调用B服务,B服务接收到请求返回调用成功,实际处理需要异步,当异步处理完成之后,再通知A,如下图:
我们希望的
B
提供的接口与回调的方式是统一的,这样B
就能实现与业务解耦,业务有增加,B
服务不需要做任何变更即可支撑。
怎么实现
1
2
步骤是同步流程,我们可以有很多方式对接B。在java微服务中,我们可以通过http的请求,可以通过mq的方式,也可以通过dubbo(rpc)。
3
步骤在java微服务中,也可以通过上述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的方式通过发送不同的队列,对应的服务进行消费。
方式有很多种,主要目的是为了让接入方,不需要编写多余的代码,完全解耦的方式实现。