@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开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!