From 92c2d79dc1ffef143149510eb685e64ba9f984bc Mon Sep 17 00:00:00 2001 From: YunaiV <> Date: Tue, 21 Jul 2020 19:45:58 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E9=87=8D=E6=96=B0=E5=AE=9E=E7=8E=B0=20Dub?= =?UTF-8?q?bo=20=E8=B7=AF=E7=94=B1=E7=9A=84=E8=BF=87=E6=BB=A4=E5=99=A8?= =?UTF-8?q?=EF=BC=8C=E4=B9=8B=E5=89=8D=E7=9A=84=E7=89=88=E6=9C=AC=E6=9C=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98=202.=20Spring=20Cloud=20Alibaba=20Dubbo=20?= =?UTF-8?q?=E7=9A=84=20URL=20=E5=A4=84=E7=90=86=E6=9C=89=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E5=88=87=E5=9B=9E=E5=88=B0=20Dubbo=20=E5=8E=9F?= =?UTF-8?q?=E7=94=9F=E6=B3=A8=E5=86=8C=E4=B8=AD=E5=BF=83=EF=BC=8C=E4=B8=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20Spring=20Cloud=20=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/mall-spring-boot-starter-dubbo/pom.xml | 10 ++- .../config/DubboWebAutoConfiguration.java | 8 ++- ...boConsumerRouterTagClusterInterceptor.java | 37 +++++++++++ .../filter/DubboProviderRouterTagFilter.java | 44 +++++++++++++ .../core/filter/DubboRouterTagFilter.java | 62 ------------------- .../router/DubboRouterTagContextHolder.java | 4 +- .../web/DubboRouterTagWebInterceptor.java | 8 ++- .../dubbo/com.alibaba.dubbo.rpc.Filter | 2 +- ...rpc.cluster.interceptor.ClusterInterceptor | 1 + mall-dependencies/pom.xml | 2 +- .../src/main/resources/application-local.yml | 8 ++- .../SystemServiceApplication.java | 4 +- .../src/main/resources/application-local.yaml | 3 +- 13 files changed, 121 insertions(+), 72 deletions(-) create mode 100644 common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/cluster/interceptor/DubboConsumerRouterTagClusterInterceptor.java create mode 100644 common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderRouterTagFilter.java delete mode 100644 common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboRouterTagFilter.java create mode 100644 common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor diff --git a/common/mall-spring-boot-starter-dubbo/pom.xml b/common/mall-spring-boot-starter-dubbo/pom.xml index 6fc1417d7..31acd196e 100644 --- a/common/mall-spring-boot-starter-dubbo/pom.xml +++ b/common/mall-spring-boot-starter-dubbo/pom.xml @@ -26,9 +26,15 @@ + + + + + + - com.alibaba.cloud - spring-cloud-starter-dubbo + org.apache.dubbo + dubbo-spring-boot-starter diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java index 7d6c9757a..92fbbd9cd 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/config/DubboWebAutoConfiguration.java @@ -1,6 +1,8 @@ package cn.iocoder.mall.dubbo.config; import cn.iocoder.mall.dubbo.core.web.DubboRouterTagWebInterceptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Configuration; @@ -11,14 +13,18 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class DubboWebAutoConfiguration implements WebMvcConfigurer { + private Logger logger = LoggerFactory.getLogger(DubboWebAutoConfiguration.class); + // ========== 拦截器相关 ========== @Override public void addInterceptors(InterceptorRegistry registry) { try { + // 设置为 -1000 的原因,保证在比较前面就处理该逻辑。例如说,认证拦截器; registry.addInterceptor(new DubboRouterTagWebInterceptor()).order(-1000); + logger.info("[addInterceptors][加载 DubboRouterTagWebInterceptor 拦截器完成]"); } catch (NoSuchBeanDefinitionException e) { -// logger.warn("[addInterceptors][无法获取 AccessLogInterceptor 拦截器,因此不启动 AccessLog 的记录]"); + logger.warn("[addInterceptors][无法获取 DubboRouterTagWebInterceptor 拦截器,无法使用 Dubbo 标签路由]"); } } diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/cluster/interceptor/DubboConsumerRouterTagClusterInterceptor.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/cluster/interceptor/DubboConsumerRouterTagClusterInterceptor.java new file mode 100644 index 000000000..4991f0da2 --- /dev/null +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/cluster/interceptor/DubboConsumerRouterTagClusterInterceptor.java @@ -0,0 +1,37 @@ +package cn.iocoder.mall.dubbo.core.cluster.interceptor; + +import cn.iocoder.common.framework.util.StringUtils; +import cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter; +import cn.iocoder.mall.dubbo.core.router.DubboRouterTagContextHolder; +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; + +/** + * Consumer 方,在调用 Provider 时,将 {@link DubboRouterTagContextHolder} 中的 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 dubboTag = DubboRouterTagContextHolder.getTag(); + if (StringUtils.hasText(dubboTag)) { + invocation.setAttachment(CommonConstants.TAG_KEY, dubboTag); + } + } + + @Override + public void after(AbstractClusterInvoker clusterInvoker, Invocation invocation) { + // 清空 Dubbo Tag 的隐式传参 + invocation.setAttachment(CommonConstants.TAG_KEY, null); + } + +} diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderRouterTagFilter.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderRouterTagFilter.java new file mode 100644 index 000000000..7051e16f8 --- /dev/null +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboProviderRouterTagFilter.java @@ -0,0 +1,44 @@ +package cn.iocoder.mall.dubbo.core.filter; + +import cn.iocoder.common.framework.util.StringUtils; +import cn.iocoder.mall.dubbo.core.cluster.interceptor.DubboConsumerRouterTagClusterInterceptor; +import cn.iocoder.mall.dubbo.core.router.DubboRouterTagContextHolder; +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,即可优先调用本地; + * 2. TODO 优化点:蓝绿发布、灰度发布 + * + * 实现逻辑为: + * 1. 对于 Consumer 方,在调用 Provider 时,{@link DubboConsumerRouterTagClusterInterceptor} 会将 {@link DubboRouterTagContextHolder} 中的 Tag 通过 Dubbo 隐式传参。 + * 同时,Dubbo 自带 {@link TagRouter},会根据该参数,会选择符合该 Tag 的 Provider。 + * 2. 对于 Provider 方,在通过 Dubbo 隐式传参获得到 Tag 时,会设置到 {@link DubboRouterTagContextHolder} 中。 + * 这样,在 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 { + // 从 Dubbo 隐式传参获得 Dubbo Tag + String dubboTag = invocation.getAttachment(CommonConstants.TAG_KEY); + boolean hasDubboTag = StringUtils.hasText(dubboTag); + if (hasDubboTag) { + invocation.setAttachment(CommonConstants.TAG_KEY, dubboTag); + } + // 继续调用 + try { + return invoker.invoke(invocation); + } finally { + // 清理 + if (hasDubboTag) { + DubboRouterTagContextHolder.clear(); + } + } + } + +} diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboRouterTagFilter.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboRouterTagFilter.java deleted file mode 100644 index 002a332cc..000000000 --- a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/filter/DubboRouterTagFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.mall.dubbo.core.filter; - -import cn.iocoder.common.framework.util.StringUtils; -import cn.iocoder.mall.dubbo.core.router.DubboRouterTagContextHolder; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.*; - -/** - * 基于 Dubbo 标签路由规则(http://dubbo.apache.org/zh-cn/docs/user/demos/routing-rule.html),实现如下功能: - * 1. 本地开发调试时,在带有 Dubbo Tag 的情况下,优先调用指定 Tag 的服务提供者。这样,我们可以将本地启动的服务提供者打上相应的 Tag,即可优先调用本地; - * 2. TODO 优化点:蓝绿发布、灰度发布 - * - * 实现逻辑为: - * 1. 对于 Consumer 方,在调用 Provider 时,会将 {@link DubboRouterTagContextHolder} 中的 Tag 通过 Dubbo 隐式传参。 - * 同时,Dubbo 自带 {@link org.apache.dubbo.rpc.cluster.router.tag.TagRouter},会根据该参数,会选择符合该 Tag 的 Provider。 - * 2. 对于 Provider 方,在通过 Dubbo 隐式传参获得到 Tag 时,会设置到 {@link DubboRouterTagContextHolder} 中。 - * 这样,在 Provider 作为 Consumer 角色时,调用其它 Provider 时,可以继续实现标签路由的功能。 - */ -@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = -1000) -public class DubboRouterTagFilter implements Filter { - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - // 消费端 - if (RpcContext.getContext().isConsumerSide()) { - // 设置 Dubbo Tag 到 Dubbo 隐式传参 - String dubboTag = DubboRouterTagContextHolder.getTag(); - boolean hasDubboTag = StringUtils.hasText(dubboTag); - if (hasDubboTag) { - invocation.setAttachment(CommonConstants.TAG_KEY, dubboTag); - } - // 继续调用 - try { - return invoker.invoke(invocation); - } finally { - // 解决极端情况下,本地 injvm 调用时,消费端会调用 DubboRouterTagContextHolder.clear() 上下文,导致消费端也被清理了,因为在同一个 JVM 进程内。 - if (hasDubboTag) { - DubboRouterTagContextHolder.setTag(dubboTag); - } - } - // 提供端 - } else { - // 从 Dubbo 隐式传参获得 Dubbo Tag - String dubboTag = invocation.getAttachment(CommonConstants.TAG_KEY); - boolean hasDubboTag = StringUtils.hasText(dubboTag); - if (hasDubboTag) { - invocation.setAttachment(CommonConstants.TAG_KEY, dubboTag); - } - // 继续调用 - try { - return invoker.invoke(invocation); - } finally { - // 清理 - if (hasDubboTag) { - DubboRouterTagContextHolder.clear(); - } - } - } - } - -} diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java index c25bd1c2e..2a658b6b2 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/router/DubboRouterTagContextHolder.java @@ -1,9 +1,11 @@ package cn.iocoder.mall.dubbo.core.router; +import cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter; + /** * Dubbo 路由 Tag 的上下文 * - * @see cn.iocoder.mall.dubbo.core.filter.DubboRouterTagFilter + * @see DubboProviderRouterTagFilter * @see cn.iocoder.mall.dubbo.core.web.DubboRouterTagWebInterceptor */ public class DubboRouterTagContextHolder { diff --git a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java index aab2363cb..c7ce62713 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java +++ b/common/mall-spring-boot-starter-dubbo/src/main/java/cn/iocoder/mall/dubbo/core/web/DubboRouterTagWebInterceptor.java @@ -1,7 +1,11 @@ package cn.iocoder.mall.dubbo.core.web; import cn.iocoder.common.framework.util.StringUtils; +import cn.iocoder.mall.dubbo.core.cluster.interceptor.DubboConsumerRouterTagClusterInterceptor; +import cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter; import cn.iocoder.mall.dubbo.core.router.DubboRouterTagContextHolder; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.rpc.RpcContext; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @@ -11,7 +15,8 @@ import javax.servlet.http.HttpServletResponse; /** * Dubbo 路由标签的 Web 拦截器,将请求 Header 中的 {@link #HEADER_DUBBO_TAG} 设置到 {@link DubboRouterTagContextHolder} 中。 * - * @see cn.iocoder.mall.dubbo.core.filter.DubboRouterTagFilter + * @see DubboProviderRouterTagFilter + * @see DubboConsumerRouterTagClusterInterceptor */ public class DubboRouterTagWebInterceptor implements HandlerInterceptor { @@ -22,6 +27,7 @@ public class DubboRouterTagWebInterceptor implements HandlerInterceptor { String tag = request.getHeader(HEADER_DUBBO_TAG); if (StringUtils.hasText(tag)) { DubboRouterTagContextHolder.setTag(tag); + RpcContext.getContext().setAttachment(CommonConstants.TAG_KEY, tag); } return true; } diff --git a/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter index b1f85b26f..f81a93f70 100644 --- a/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +++ b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter @@ -1,2 +1,2 @@ dubboExceptionFilter=cn.iocoder.mall.dubbo.core.filter.DubboProviderExceptionFilter -dubboRouterTagFilter=cn.iocoder.mall.dubbo.core.filter.DubboRouterTagFilter +dubboProviderRouterTagFilter=cn.iocoder.mall.dubbo.core.filter.DubboProviderRouterTagFilter diff --git a/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor new file mode 100644 index 000000000..bba113398 --- /dev/null +++ b/common/mall-spring-boot-starter-dubbo/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor @@ -0,0 +1 @@ +dubboConsumerRouterTagClusterInterceptor=cn.iocoder.mall.dubbo.core.cluster.interceptor.DubboConsumerRouterTagClusterInterceptor diff --git a/mall-dependencies/pom.xml b/mall-dependencies/pom.xml index 78e5b952e..64255fcc6 100644 --- a/mall-dependencies/pom.xml +++ b/mall-dependencies/pom.xml @@ -41,7 +41,7 @@ 3.1.1 3.2.5.RELEASE - 2.7.6 + 2.7.7 2.0.1 diff --git a/management-web-app/src/main/resources/application-local.yml b/management-web-app/src/main/resources/application-local.yml index 2e9e99973..b03881072 100644 --- a/management-web-app/src/main/resources/application-local.yml +++ b/management-web-app/src/main/resources/application-local.yml @@ -11,4 +11,10 @@ spring: dubbo: # Dubbo 注册中心 registry: - address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址 +# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址 +# address: nacos://400-infra.server.iocoder.cn:8848?namespace=local # 指定 Dubbo 服务注册中心的地址 + protocol: nacos + address: 400-infra.server.iocoder.cn:8848?namespace=local + timeout: 20000 + register: true + subscribe: true diff --git a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/SystemServiceApplication.java b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/SystemServiceApplication.java index 13349c96a..7c1623bbb 100644 --- a/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/SystemServiceApplication.java +++ b/system-service-project/system-service-app/src/main/java/cn/iocoder/mall/systemservice/SystemServiceApplication.java @@ -2,12 +2,14 @@ package cn.iocoder.mall.systemservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class SystemServiceApplication { public static void main(String[] args) { - SpringApplication.run(SystemServiceApplication.class, args); + ConfigurableApplicationContext context = SpringApplication.run(SystemServiceApplication.class, args); + System.out.println(context); } } diff --git a/system-service-project/system-service-app/src/main/resources/application-local.yaml b/system-service-project/system-service-app/src/main/resources/application-local.yaml index bf97cae95..e15afd4d1 100644 --- a/system-service-project/system-service-app/src/main/resources/application-local.yaml +++ b/system-service-project/system-service-app/src/main/resources/application-local.yaml @@ -17,4 +17,5 @@ spring: dubbo: # Dubbo 注册中心 registry: - address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址 +# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址 + address: nacos://400-infra.server.iocoder.cn:8848?namespace=local # 指定 Dubbo 服务注册中心的地址