背景
当我们开发工具类时、需要调用dubbo服务的情况下、往往不希望添加dubbo的xml配置文件。
否则开发好的工具栏调用太不友好。
解决方案
方案一:静态调用
调用示例(方案一)
@Test
public void testDubboNoGenericService(){
UserService userService = DubboUtils.getService(
UserService.class, "1.0.0");
UserDto userDto = userService.getUserByIdentify("admin");
System.out.println(userDto.getRealname());
}
调用示例(方案二)
@Test
public void testDubboGenericService(){
Object result = DubboUtils.callGenericService(
"com.tyyd.xroic.api.service.UserService",
"getUserByIdentify", "1.0.0",
new String[]{"java.lang.String"},
new Object[]{"admin"});
System.out.println(result);
}
实现代码
package com.acws.ext.dubbo;
import com.acws.core.AcwsInfo;
import com.acws.core.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DubboUtils {
private static final Logger logger = LoggerFactory.getLogger(DubboUtils.class);
public static final Map<String, Object> serviceMap = new HashMap<>();
/**
* 取得Dubbo bean
* @param clazz
* @param version
* @param tag 可以不传 不传的话取system环境变量
* @param <T>
* @return
*/
public static <T> T getService(Class<T> clazz, String version, String... tag) {
if(clazz == null || StringUtils.isBlank(version)) {
throw new IllegalArgumentException("DubboUtils#getService():参数不能为空.");
}
String key = StringUtil.addString(clazz.getName(), ":", version);
Object objService = serviceMap.get(key);
if(objService!= null && !StringUtils.equals(objService.getClass().getName(), clazz.getName())) {
throw new IllegalArgumentException("DubboUtils#getService():返回值类型不符.期望:"+clazz.getName()+
",实际:"+objService.getClass().getName());
}
if(serviceMap.containsKey(key)) {
return (T) objService;
}
ReferenceConfig reference = createReferenceConfig();
// 设置tag:用于灰度发布、线上程序调试
String tagEnv = getTag(tag);
if (StringUtils.isNotBlank(tagEnv)) {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTag(tagEnv);
reference.setConsumer(consumerConfig);
}
reference.setVersion(version);
// 弱类型接口名
reference.setInterface(clazz);
// 声明为泛化接口
reference.setGeneric("fasle");
objService = reference.get();
serviceMap.put(key, objService);
return (T)objService;
}
/**
* 取得Dubbo Bean
* @param clazz
* @param methodName
* @param version
* @param paramsClassName
* @param params
* @param tag 可以不传 不传的话取system环境变量
* @return
*/
public static Object callGenericService(String clazz, String methodName, String version, String[] paramsClassName, Object[] params, String... tag) {
if(StringUtils.isBlank(clazz) || StringUtils.isBlank(methodName)) {
throw new IllegalArgumentException("DubboUtils#callGenericService():参数不能为空.packageName="+clazz+",methodName="+methodName);
}
if((paramsClassName!=null && params == null) || (paramsClassName==null && params!= null)) {
throw new IllegalArgumentException("DubboUtils#callGenericService():参数设置错误.paramsClassName="+clazz+",params="+params);
}
if((paramsClassName != null && params != null) && (paramsClassName.length != params.length)) {
throw new IllegalArgumentException("DubboUtils#callGenericService():参数设置错误.paramsClassName="+clazz+",params="+params);
}
String key = StringUtil.addString(clazz, ".", methodName, ":", version, ":gen");
Object objService = serviceMap.get(key);
if(objService!=null && !(objService instanceof GenericService)) {
throw new IllegalArgumentException("DubboUtils#callGenericService():返回值类型不符.期望:GenericService,实际:"+objService.getClass().getName());
}
if(serviceMap.containsKey(key) && objService == null) {
throw new IllegalArgumentException("DubboUtils#callGenericService():获取远程bean失败.");
}
if(objService == null) {
ReferenceConfig reference = createReferenceConfig();
// 设置tag:用于灰度发布、线上程序调试
String tagEnv = getTag(tag);
if (StringUtils.isNotBlank(tagEnv)) {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTag(tagEnv);
reference.setConsumer(consumerConfig);
}
reference.setVersion(version);
// 弱类型接口名
reference.setInterface(clazz);
// 声明为泛化接口
reference.setGeneric("true");
objService = reference.get();
serviceMap.put(key, objService);
}
// 基本类型以及Date,List,Map等不需要转换,直接调用
GenericService genericService = (GenericService) objService;
return genericService.$invoke(methodName, paramsClassName, params);
}
private static ReferenceConfig createReferenceConfig() {
// 普通编码配置方式
ApplicationConfig application = new ApplicationConfig();
// 客户端应用名:可以任意取名
application.setName("acws-dubbo-generic-" + AcwsInfo.getAcwsAppShortName());
application.setLogger("slf4j");
// 连接注册中心配置
RegistryConfig registry1 = new RegistryConfig();
registry1.setAddress("zookeeper://vr-zk-1.189read.com:2181");
RegistryConfig registry2 = new RegistryConfig();
registry2.setAddress("zookeeper://vr-zk-2.189read.com:2181");
List<RegistryConfig> registries = new ArrayList<>();
registries.add(registry1);
registries.add(registry2);
// 引用远程服务
// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存
ReferenceConfig reference = new ReferenceConfig();
reference.setApplication(application);
reference.setRegistries(registries);
reference.setCheck(false);
return reference;
}
private static String getTag(String... tag) {
String tagEnv = System.getProperty("dubbo.provider.tag");
if (tag != null && tag.length > 0 && StringUtils.isNotBlank(tag[0])) {
tagEnv = tag[0];
}
return tagEnv;
}
}