Dubbo下的多版本并行开发测试解决方案(服务路由)

@Override

public URL getUrl() {

return DevVersionRegisterFactoryWrapper.changeApplication(registry.getUrl());

}

@Override

public boolean isAvailable() {

return registry.isAvailable();

}

@Override

public void destroy() {

registry.destroy();

}

@Override

public void register(URL url) {

registry.register(DevVersionRegisterFactoryWrapper.changeApplication((url)));

}

@Override

public void unregister(URL url) {

registry.register(DevVersionRegisterFactoryWrapper.changeApplication((url)));

}

@Override

public void subscribe(URL url, NotifyListener listener) {

registry.subscribe(DevVersionRegisterFactoryWrapper.changeApplication((url)),listener);

}

@Override

public void unsubscribe(URL url, NotifyListener listener) {

registry.unsubscribe(DevVersionRegisterFactoryWrapper.changeApplication((url)),listener);

}

@Override

public List lookup(URL url) {

return registry.lookup(DevVersionRegisterFactoryWrapper.changeApplication((url)));

}

}

写一个RegistryFactory的包装类

/**

  • @author shirenchuang

  • RegistryFactory 的包装类,在注册的时候 修改一下 Application

  • 如果是 迭代环境则把Appliacation=Application_迭代版本号

  • @date 2019/12/5 8:29 下午

*/

public class DevVersionRegisterFactoryWrapper implements RegistryFactory {

private static final Logger logger = LoggerFactory.getLogger(“devVersion”);

private RegistryFactory registryFactory;

/**

  • 注入RegisterFactory

*/

public DevVersionRegisterFactoryWrapper(RegistryFactory registryFactory) {

this.registryFactory = registryFactory;

}

@Override

public Registry getRegistry(URL url) {

//获取当前环境的迭代版本号

if(!StringUtils.isEmpty(MyThreadLocal.localVersion)){

logger.info(“=启动的服务是迭代版本服务 devVersion:{}=”,MyThreadLocal.localVersion);

System.out.println(“====启动的服务是迭代版本服务 devVersion:”+MyThreadLocal.localVersion);

return new DevVersionRegisterWrapper(registryFactory.getRegistry(changeApplication(url)));

}

logger.info(“=启动的服务是稳定版本”);

System.out.println(“=启动的服务是稳定版本”);

return registryFactory.getRegistry(url);

}

public static URL changeApplication(URL url){

if(!StringUtils.isEmpty(MyThreadLocal.localVersion)){

String applicationKey = url.getParameter(Constants.APPLICATION_KEY)+MyThreadLocal.spiltString+MyThreadLocal.localVersion;

URL url2 = url.addParameter(Constants.APPLICATION_KEY,

applicationKey);

logger.info(“=====迭代版本服务修改 Application key:{} =====”,applicationKey);

return url2;

}

return url;

}

}

服务路由

Invoker 包装类

/**

  • @author shirenchuang

  • 2019/12/10

  • 集群扩展包装器

  • 参照 {@link com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker}

*/

public class DevVersionClusterInvoker implements Invoker {

private static final Logger logger = LoggerFactory.getLogger(“devVersion”);

private final Directory directory;

private final Invoker invoker;

public DevVersionClusterInvoker(Directory directory, Invoker invoker) {

this.directory = directory;

this.invoker = invoker;

}

@Override

public URL getUrl() {

return directory.getUrl();

}

@Override

public boolean isAvailable() {

return directory.isAvailable();

}

@Override

public void destroy() {

this.invoker.destroy();

}

@Override

public Class getInterface() {

return directory.getInterface();

}

@Override

public Result invoke(Invocation invocation) throws RpcException {

// 找到迭代版本号

return doDevVersionInvoke(invocation, null);

}

@SuppressWarnings({“unchecked”, “rawtypes”})

private Result doDevVersionInvoke(Invocation invocation, RpcException e) {

Result result ;

Invoker minvoker;

List<Invoker> devVersionInvokers = selectDevVersionInvoker(invocation);

if (devVersionInvokers==null||devVersionInvokers.size()==0) {

logger.error("没有找到服务啊~~~~ ");

throw new RpcException(“没有找到服务啊~~~~”);

} else {

minvoker = devVersionInvokers.get(0);

}

try {

result = minvoker.invoke(invocation);

} catch (RpcException me) {

if (me.isBiz()) {

result = new RpcResult(me.getCause());

} else {

throw new RpcException(me.getCode(), getDevVersionExceptionMessage(e, me), me.getCause());

}

} catch (Throwable me) {

throw new RpcException(getDevVersionExceptionMessage(e, me), me.getCause());

}

return result;

}

private String getDevVersionExceptionMessage(Throwable t, Throwable mt) {

String msg = "devVersion error : " + mt.getMessage();

if (t != null) {

msg = msg + “, invoke error is :” + StringUtils.toString(t);

}

return msg;

}

/**

  • 获取对应迭代版本服务

  • @param invocation

  • @return

*/

private List<Invoker> selectDevVersionInvoker(Invocation invocation) {

List<Invoker> invokers = null;

if (invocation instanceof RpcInvocation) {

try {

/其实我们也可以给directory生生一个代理类,来做帅选操作/

invokers = directory.list(invocation);

//经过了dubbo的栓选之后,我们来找自己需要的Invokes

String devVersion = MyThreadLocal.getDevVersion();

List<Invoker> newInvokers = new ArrayList<>();

List<Invoker> stableInvokers = new ArrayList<>();

for (Invoker invoker : invokers){

URL providerUrl ;

//获取应用名称

Method getProviderUrl = invoker.getClass().getDeclaredMethod(“getProviderUrl”);

getProviderUrl.setAccessible(true);

providerUrl = (URL)getProviderUrl.invoke(invoker);

String application = providerUrl.getParameter(Constants.APPLICATION_KEY);

if(StringUtils.isEmpty(devVersion)){

if(application.indexOf(MyThreadLocal.spiltString)==-1){

//不是迭代过来或者本身不是迭代的请求 只能访问非迭代版本

newInvokers.add(invoker);

}

}else {

//是迭代的请求 就需要找对应的迭代服务

if(application.indexOf(MyThreadLocal.spiltString)!=-1){

String version = application.substring(application.indexOf(MyThreadLocal.spiltString)+5);

if(version.equals(devVersion)){

newInvokers.add(invoker);

}

}

}

//找到稳定环境

if(application.indexOf(MyThreadLocal.spiltString)==-1){

stableInvokers.add(invoker);

}

}

if(newInvokers==null||newInvokers.size()==0){

String serviceName = directory.getInterface().getName();

if(StringUtils.isEmpty(devVersion)){

String error = “=====当前消费者自身版本和迭代传递版本均为稳定版本~ ,但是没有找到将要消费的服务=>”+serviceName+" 的稳定版本!!";

logger.error(error);

throw new RuntimeException(error);

}else {

// 请求的是迭代服务, 但是迭代服务没有找到,退而求其次调用稳定环境 )

if(stableInvokers!=null&&stableInvokers.size()>0){

StringBuffer sb = new StringBuffer();

sb.append(“=======当前cap请求的版本为:”).append(devVersion)

.append(“;往后传递版本”).append(devVersion).append(“; 将要消费的服务:”).append(serviceName)

.append(“没有找到与之对应的迭代版本;将会调用稳定版本”);

logger.info(sb.toString());

return stableInvokers;

}else {

//可能有其他的迭代服务,但是不调用

logger.error(“当前请求迭代版本:{},但是不存在迭代服务,也没有找到稳定服务;{},{},{}”,devVersion,serviceName);

throw new RuntimeException(“当前请求迭代版本:”+devVersion+“,但是不存在迭代服务,也没有找到稳定服务;”+serviceName);

}

}

}else {

return newInvokers;

}

} catch (RpcException e) {

logger.error(“获取 迭代版本 的服务时 发生错误~~:”+ directory.getUrl().getServiceInterface() + “, method:” + invocation.getMethodName()

, e);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

return invokers;

}

@Override

public String toString() {

return “invoker :” + this.invoker + ",directory: " + this.directory;

}

public static void main(String[] args) {

String application = “application”+MyThreadLocal.spiltString+“1.0.1”;

boolean b = application.indexOf(MyThreadLocal.spiltString)==-1;

application = application.substring(application.indexOf(MyThreadLocal.spiltString)+5);

System.out.print(application);

}

}

/**

  • @author shirenchuang

  • 2019/12/10

  • 集群扩展包装器

  • 参照 {@link com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker}

*/

public class DevVersionClusterWrapper implements Cluster {

private Cluster cluster;

public DevVersionClusterWrapper(Cluster cluster) {

this.cluster = cluster;

}

@Override

public Invoker join(Directory directory) throws RpcException {

//如果自己是迭代环境,则使用包装

return new DevVersionClusterInvoker(directory,

this.cluster.join(directory));

}

}

拦截器 带入 标签Version

消费者拦截器

/**

  • @Description 消费别人服务的时候会走到这里

  •          要把 迭代版本号 放到参数里面传到 服务提供者
    
  • @Author shirenchuang

  • @Date 2019/12/1 10:20 PM

**/

@Activate(group = {Constants.CONSUMER})

public class DevVersionConsumerFilter implements Filter {

private static final Logger logger = LoggerFactory.getLogger(“devVersion”);

@Override

public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

String traceId = TraceUtil.getTraceId();

RpcContext.getContext().setAttachment(“myTraceId”,traceId);

String toDevVersion = MyThreadLocal.getDevVersion();

RpcContext.getContext().setAttachment(“devVersion”,toDevVersion);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
();

RpcContext.getContext().setAttachment(“devVersion”,toDevVersion);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-pKhZ1cwS-1715667906346)]

[外链图片转存中…(img-srHDp9UL-1715667906347)]

[外链图片转存中…(img-zeIhEy36-1715667906347)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值