移除 Dubbo 依赖,Dubbo 在国内使用率太低

This commit is contained in:
YunaiV
2023-07-28 19:20:27 +08:00
parent 3930fd739a
commit 7f7a3c589b
45 changed files with 24 additions and 389 deletions

View File

@@ -56,15 +56,6 @@
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-cluster</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>

View File

@@ -13,16 +13,14 @@ import static cn.iocoder.yudao.framework.env.core.util.EnvUtils.HOST_NAME_VALUE;
/**
* 多环境的 {@link EnvEnvironmentPostProcessor} 实现类
* 将 yudao.env.tag 设置到 dubbo、nacos 等组件对应的 tag 配置项,当且仅当它们不存在时
* 将 yudao.env.tag 设置到 nacos 等组件对应的 tag 配置项,当且仅当它们不存在时
*
* @author 芋道源码
*/
public class EnvEnvironmentPostProcessor implements EnvironmentPostProcessor {
private static final Set<String> TARGET_TAG_KEYS = SetUtils.asSet(
"spring.cloud.nacos.discovery.metadata.tag", // Nacos 注册中心
"dubbo.provider.tag", // Dubbo 服务提供者的 tag
"dubbo.consumer.tag" // Dubbo 服务消费者的 tag
"spring.cloud.nacos.discovery.metadata.tag" // Nacos 注册中心
// MQ TODO
);

View File

@@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
@@ -24,24 +25,10 @@ public class YudaoEnvRpcAutoConfiguration {
// ========== Feign 相关 ==========
// TODO @芋艿:由于 loadBalancerClientFactoryBeanPostProcessor 拦截不到 LoadBalancerClientFactory所以采用 loadBalancerClientFactory 实现
// @Bean
// public BeanPostProcessor loadBalancerClientFactoryBeanPostProcessor(LoadBalancerClientsProperties properties) {
// return new BeanPostProcessor() {
// @Override
// public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// if (!(bean instanceof LoadBalancerClientFactory)) {
// return bean;
// }
// return bean;
// }
// };
// }
/**
* 创建 {@link EnvLoadBalancerClientFactory} Bean
*
* 参考 {@link org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration#loadBalancerClientFactory(LoadBalancerClientsProperties)} 方法
* 参考 {@link LoadBalancerAutoConfiguration#loadBalancerClientFactory(LoadBalancerClientsProperties)} 方法
*/
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties,
@@ -56,6 +43,4 @@ public class YudaoEnvRpcAutoConfiguration {
return new EnvRequestInterceptor();
}
// ========== Dubbo 相关 ==========
}

View File

@@ -1,36 +0,0 @@
package cn.iocoder.yudao.framework.env.core.dubbo;
import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
import org.springframework.util.StringUtils;
/**
* Consumer 方,在调用 Provider 时,将 {@link EnvContextHolder} 中的 Tag 通过 Dubbo 隐式传参。
*
* 完整逻辑说明,见 {@link DubboProviderRouterTagFilter}
*
* 注意,这里需要设置到 order = 1 的原因,是需要保证排在 ConsumerContextClusterInterceptor 之后
*/
@Activate(group = CommonConstants.CONSUMER, order = 1)
public class DubboConsumerRouterTagClusterInterceptor implements ClusterInterceptor {
@Override
public void before(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation) {
// 设置 Dubbo Tag 到 Dubbo 隐式传参
String tag = EnvContextHolder.getTag();
if (StringUtils.hasText(tag)) {
invocation.setAttachment(CommonConstants.TAG_KEY, tag);
}
}
@Override
public void after(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation) {
// 清空 Dubbo Tag 的隐式传参
invocation.setAttachment(CommonConstants.TAG_KEY, null);
}
}

View File

@@ -1,43 +0,0 @@
package cn.iocoder.yudao.framework.env.core.dubbo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.env.core.context.EnvContextHolder;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.cluster.router.tag.TagRouter;
/**
* 基于 Dubbo 标签路由规则(http://dubbo.apache.org/zh-cn/docs/user/demos/routing-rule.html),实现如下功能:
* 1. 本地开发调试时,在带有 Dubbo Tag 的情况下,优先调用指定 Tag 的服务提供者。这样,我们可以将本地启动的服务提供者打上相应的 Tag即可优先调用本地
* 并且,前端在调用开发环境上的 Dubbo 服务时,因为不带有 Dubbo Tag所以不会调用到后端开发本地启动的 Dubbo 服务提供者;
* 2. TODO 优化点:蓝绿发布、灰度发布
*
* 实现逻辑为:
* 1. 对于 Consumer 方,在调用 Provider 时,{@link DubboConsumerRouterTagClusterInterceptor} 会将 {@link EnvContextHolder} 中的 Tag 通过 Dubbo 隐式传参。
* 同时Dubbo 自带 {@link TagRouter},会根据该参数,会选择符合该 Tag 的 Provider。
* 2. 对于 Provider 方,在通过 Dubbo 隐式传参获得到 Tag 时,会设置到 {@link EnvContextHolder} 中。
* 这样,在 Provider 作为 Consumer 角色时,调用其它 Provider 时,可以继续实现标签路由的功能。
*/
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = -1000)
public class DubboProviderRouterTagFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 情况一,没有 tag 时,直接调用即可
String tag = invocation.getAttachment(CommonConstants.TAG_KEY);
if (StrUtil.isEmpty(tag)) {
return invoker.invoke(invocation);
}
// 情况二,有 tag 时,从 Dubbo 隐式传参获得 Dubbo Tag
EnvContextHolder.setTag(tag);
// 继续调用
try {
return invoker.invoke(invocation);
} finally {
EnvContextHolder.removeTag();
}
}
}

View File

@@ -1,14 +1,13 @@
package cn.iocoder.yudao.framework.env.core.util;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.env.config.EnvProperties;
import feign.RequestTemplate;
import lombok.SneakyThrows;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.env.Environment;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.util.Objects;
/**
@@ -44,8 +43,14 @@ public class EnvUtils {
requestTemplate.header(HEADER_TAG, tag);
}
/**
* 获得 hostname 主机名
*
* @return 主机名
*/
@SneakyThrows
public static String getHostName() {
return StrUtil.blankToDefault(NetUtil.getLocalHostName(), IdUtil.fastSimpleUUID());
return InetAddress.getLocalHost().getHostName();
}
}

View File

@@ -1 +0,0 @@
dubboProviderRouterTagFilter=cn.iocoder.yudao.framework.env.core.dubbo.DubboProviderRouterTagFilter

View File

@@ -1 +0,0 @@
dubboConsumerRouterTagClusterInterceptor=cn.iocoder.yudao.framework.env.core.dubbo.DubboConsumerRouterTagClusterInterceptor

View File

@@ -14,7 +14,6 @@
<name>${project.artifactId}</name>
<description>
OpenFeign提供 RESTful API 的调用
Dubbo提供 Dubbo RPC 的调用
</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
@@ -34,20 +33,6 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId> <!-- 兜底,保证在不引入 spring-cloud-starter-dubbo 时,注解等不报错 -->
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId> <!-- 兜底,保证在不引入 spring-cloud-starter-dubbo 时,注解等不报错 -->
</dependency>
<!-- -->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-dubbo</artifactId>-->
<!-- </dependency>-->
<!-- 工具相关 -->
<dependency>
<groupId>jakarta.validation</groupId>

View File

@@ -1,110 +0,0 @@
package cn.iocoder.yudao.framework.rpc.core.dubbo;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.iocoder.yudao.framework.common.exception.ServerException;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.service.GenericService;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.Type;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
@Activate(group = CommonConstants.PROVIDER) // TODO 优化点:设置下顺序
@Slf4j
public class DubboProviderExceptionFilter implements Filter, Filter.Listener {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
try {
// 1. 转换异常
Throwable exception = appResponse.getException();
// 1.1 参数校验异常
if (exception instanceof ConstraintViolationException) {
exception = this.constraintViolationExceptionHandler((ConstraintViolationException) exception);
// 1. ServiceException 业务异常,因为不会有序列化问题,所以无需处理
} else if (exception instanceof ServiceException) {
// 1.3 其它异常,转换成 GlobalException 全局异常,避免可能存在的反序列化问题
} else {
exception = this.defaultExceptionHandler(exception, invocation);
assert exception != null;
}
// 2. 根据不同的方法 schema 返回结果
// 2.1 如果是 ServiceException 异常,并且返回参数类型是 CommonResult 的情况,则将转换成 CommonResult 返回
if (isReturnCommonResult(invocation) && exception instanceof ServiceException) {
appResponse.setException(null); // 一定要清空异常
appResponse.setValue(CommonResult.error((ServiceException) exception));
// 2.2 如果是 GlobalException 全局异常,则直接抛出
} else {
// TODO 优化点:尝试修改成 RpcException
appResponse.setException(exception);
}
} catch (Throwable e) {
log.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
}
}
}
@Override
public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
log.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
}
private boolean isReturnCommonResult(Invocation invocation) {
if (!(invocation instanceof RpcInvocation)) {
return false;
}
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
Type[] returnTypes = rpcInvocation.getReturnTypes();
if (returnTypes.length == 0) {
return false;
}
Type returnType = returnTypes[0];
if (!(returnType instanceof Class)) {
return false;
}
Class<?> returnClass = (Class<?>) returnType;
return returnClass == CommonResult.class;
}
/**
* 处理 Validator 校验不通过产生的异常
*/
private ServiceException constraintViolationExceptionHandler(ConstraintViolationException ex) {
log.warn("[constraintViolationExceptionHandler]", ex);
ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
return new ServiceException(BAD_REQUEST.getCode(),
String.format("请求参数不正确:%s", constraintViolation.getMessage()));
}
/**
* 处理系统异常,兜底处理所有的一切
*/
private ServerException defaultExceptionHandler(Throwable exception, Invocation invocation) {
log.error("[defaultExceptionHandler][service({}) method({}) params({}) 执行异常]",
invocation.getTargetServiceUniqueName(), invocation.getMethodName(), invocation.getArguments(), exception);
// 如果已经是 GlobalException 全局异常,直接返回即可
if (exception instanceof ServerException) {
return (ServerException) exception;
}
return new ServerException(INTERNAL_SERVER_ERROR).setMessage(this.buildDetailMessage(exception, invocation));
}
private String buildDetailMessage(Throwable exception, Invocation invocation) {
return String.format("Service(%s) Method(%s) 发生异常(%s)",
invocation.getTargetServiceUniqueName(), invocation.getMethodName(), ExceptionUtil.getRootCauseMessage(exception));
}
}

View File

@@ -1,6 +1,5 @@
/**
* OpenFeign提供 RESTful API 的调用
* Dubbo提供 Dubbo RPC 的调用
*
* @author 芋道源码
*/

View File

@@ -1 +0,0 @@
dubboExceptionFilter=cn.iocoder.yudao.framework.rpc.core.dubbo.DubboProviderExceptionFilter

View File

@@ -1 +0,0 @@
<http://www.iocoder.cn/Spring-Boot/Dubbo/?yudao>

View File

@@ -1 +0,0 @@
<http://www.iocoder.cn/Spring-Cloud-Alibaba/Dubbo/?yudao>