日常开发中,使用dubbo的场景为:
(1)A业务依赖B业务的能力,B业务开发好dubbo接口,把接口定义(方法、出入参DTO、enum、constants等)打在二方包,由A应用在pom中引用依赖包;
(2)B应用启动服务,如通过@DubboService注解并指定version、timeout、group等把处理逻辑的service注册为bean,暴露dubbo接口的地址到zk;
(3)A应用启动服务,如通过@DubboReference注解并指定version、timeout、group等把B的接口注册为bean,在代码中调用接口的方法(通过查找zk的服务方地址远程RPC调用);
现在有一种新的场景,A提供接口规范(方法及出入参),由B、C、D等多个业务方来实现这个接口,并将各自的服务以dubbo的形式注册到zk(以group区分);A在业务处理逻辑中,通过业务参数找到对应的group,然后在代码中调用对应group的dubbo接口;
因为业务方的数量是不确定的,也就是说A不知道当前有哪些接入方,因此不能提前在代码中使用@DubboReference注解配置各个provider的bean,仅知道自己定义的接口定义和给各个业务方分配的默认group;这时,就需要A在代码中能「编程式动态」调用dubbo;
下面给出代码实例:
(1)A应用定义的接口规范
/**
* A应用定义的接口规范
*/
public interface BaseFacade {
/**
* 查询
*
* @param requestDTO
* @return
*/
Return<String> query(RequestDTO requestDTO);
}
(2)B、C、D等多个业务方来实现这个接口,配置好group,部署服务注册到zk
/**
* 实现A应用定义的接口规范
*/
@Slf4j
@DubboService(group = "${baseFacade .group}", version = "1.0.0", timeout = 5000)
public class BaseFacadeImpl implements BaseFacade {
@Override
public Return<String> query(RequestDTO requestDTO) {
// ...
}
}
(3)A应用编程式调用B、C、D的dubbo接口(理论上ZK的dubbo服务都可以泛化调用)
/**
* @author Akira
*/
@Slf4j
@Service
public class SimpleDynamicInvoker {
/**
* dubbo provider 缓存
*/
private static final Map<String, BaseFacade> servicesCache = Maps.newConcurrentMap();
/**
* A定义的接口名
*/
private static final String INTERFACE_NAME = BaseFacade.class.getName();
@Resource
private DefaultListableBeanFactory beanFactory;
/**
* 根据groupId初始化对应的provider
*
* @param groupId
*/
private void initProvider(String groupId) {
if (servicesCache.containsKey(groupId)) {
return;
}
String beanId = "BaseFacade#" + groupId;
RootBeanDefinition serviceBeanDefinition = new RootBeanDefinition();
// class为org.apache.dubbo.config.spring.ReferenceBean
serviceBeanDefinition.setBeanClass(ReferenceBean.class);
serviceBeanDefinition.setLazyInit(false);
serviceBeanDefinition.getPropertyValues().addPropertyValue("version", "1.0.0");
serviceBeanDefinition.getPropertyValues().addPropertyValue("interface", INTERFACE_NAME);
serviceBeanDefinition.getPropertyValues().addPropertyValue("group", groupId);
serviceBeanDefinition.getPropertyValues().addPropertyValue("id", beanId);
beanFactory.registerBeanDefinition(beanId, serviceBeanDefinition);
// 注册bean 返回bean实例
BaseFacade facadeBean = beanFactory.getBean(beanId, BaseFacade.class);
servicesCache.put(groupId, facadeBean);
log.info("注册provider成功. [groupId={}]", groupId);
}
/**
* 执行provider调用
*
* @param groupId
* @param param
* @return
*/
public Return<String> invokeByGroupId(String groupId, RequestDTO param) {
if (!servicesCache.containsKey(groupId)) {
initProvider(groupId);
}
final BaseFacade baseFacade = servicesCache.get(groupId);
return baseFacade.query(param);
}
}
参考: