Skip to content

Commit

Permalink
add compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
diecui1202 committed Sep 4, 2018
1 parent 21d0500 commit 469b327
Show file tree
Hide file tree
Showing 27 changed files with 433 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 主要讲述如何配置dubbo,按照配置方式上可以分为
---

# Dubbo基本用法之Provider配置
---


## Dubbo基本用法

Expand Down
197 changes: 197 additions & 0 deletions blog/zh-cn/dubbo-compatible.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
---
title: Dubbo 2.7.x repackage后的兼容实现方案
keywords: Dubbo, repackage, 兼容
description: 本文简单描述了2.7.x repackage后对老版本的兼容性实现方案。
---

# Dubbo 2.7.x repackage后的兼容实现方案

Dubbo至加入Apache孵化器以来,一个很强的诉求就是需要rename groupId和package name,这两项工作在项目毕业前需要完成。其中rename package相对来说复杂一些,除了要修改所有类的包名为`org.apache.dubbo`外,更多的是需要考虑如何老版本的兼容性。

常见的兼容性包括但不限于以下几种情况:

* 用户API
* 编程API
* Spring注解
* 扩展SPI
* 扩展Filter

2.7.x里就是通过增加了一个新的模块`dubbo-compatible`来解决以上兼容性问题。

## 编程使用API

编程使用API是最直接最原始的使用方式,其他方式诸如Spring schema、注解等方式都是基于原始API的;因此非常有必要对API编程形式进行兼容。

所有编程相关API的兼容代码均在`com.alibaba.dubbo.config`包下,下面我们看看几个常见API的兼容实现。

### ApplicationConfig

```java
package com.alibaba.dubbo.config;

@Deprecated
public class ApplicationConfig extends org.apache.dubbo.config.ApplicationConfig {

public ApplicationConfig() {
super();
}

public ApplicationConfig(String name) {
super(name);
}
}
```

### ProtocolConfig

```java
package com.alibaba.dubbo.config;

@Deprecated
public class ProtocolConfig extends org.apache.dubbo.config.ProtocolConfig {

public ProtocolConfig() {
}

public ProtocolConfig(String name) {
super(name);
}

public ProtocolConfig(String name, int port) {
super(name, port);
}
}
```

可以看到:

1. 兼容类是直接通过继续repacakge后的类,达到最大程度的代码复用;
2. 构造函数也需要保持兼容;

整个兼容包中,除了上述API以外,包括一些常用的类比如`Constants``URL`以及绝大部分的兼容类都是通过简单的继承,让用户基于老的API实现的类能正确运行。

## Spring注解

Spring注解诸如`@EnableDubbo``@Service`以及`@Reference`,由于不能使用继承,故这些注解类是通过代码拷贝来实现的;用于处理这些注解的Spring BeanPostProcessor以及Parser等相关的类,也是通过拷贝来实现;

这类兼容代码分别位于兼容包的以下几个package中:

* com.alibaba.dubbo.config.annotation
* com.alibaba.dubbo.config.spring.context.annotation
* org.apache.dubbo.config.spring

所以这里要特别强调的是,这类代码在2.7.x里存在2份,因此有修改的同时需要同步修改。

## 扩展SPI

Dubbo的SPI扩展机制,可以通过[Dubbo可扩展机制实战](http://dubbo.apache.org/zh-cn/blog/introduction-to-dubbo-spi.html)这篇博客详细了解。

以Filter扩展为例,简单来说就是:

1. MyFilter需要实现Filter接口
2. 在META-INF/dubbo下,增加META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,内容为:

```
myFilter=com.test.MyFilter
```

看似简单的两点,对Dubbo框架来说,需要:

1. 正确加载配置文件META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
2. 正确加载MyFilter类并执行invoke方法

下面分别介绍Dubbo框架怎么实现以上几点。

### 正确加载META-INF/dubbo/com.alibaba.dubbo.rpc.Filter

Dubbo SPI机制在查找配置文件时,是根据扩展点的类名来查找的,以Filter为例,在包名变为org.apache.dubbo后,查询的目录变成:

* META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter
* META-INF/dubbo/org.apache.dubbo.rpc.Filter
* META-INF/services/org.apache.dubbo.rpc.Filter

但是用户之前按老的包实现的Filter,其配置是放在类似`META-INF/dubbo/com.alibaba.dubbo.rpc.Filter`的,如果框架不做特殊处理,是不会加载老配置的。

因此在`ExtensionLoader`这个类里,做了特殊的处理:

```java
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if (names.length == 1) cachedDefaultName = names[0];
}
}

Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
```

可以看到,除了加载新配置外,老配置文件也会进行扫描。

### 正确加载MyFilter类

`com.alibaba.dubbo.rpc.Filter`接口除了要继承自`org.apache.dubbo.rpc.Filter`以外,其唯一的方法invoke也需要做特殊处理。我们看看它的方法签名:

`Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;`

这里参数、返回值、异常都会被实现类`MyFilter`用到,因此这些类也需要有兼容类;而参数、返回值不同,对于接口来说是不同的方法,因此:

* 需要在com.alibaba.dubbo.rpc.Filter里,定义老的invoke方法,MyFilter会覆盖这个方法;
* org.apache.dubbo.rpc.Filter里的invoke方法,需要找一个地方来实现桥接,框架调用Filter链执行到新的invoke方法时,新的参数如何转换成老参数,老返回值如何转换成新的返回值;

这里就用到了JDK8的新特性:接口default方法。

```java
@Deprecated
public interface Filter extends org.apache.dubbo.rpc.Filter {

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

default org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invoker<?> invoker,
org.apache.dubbo.rpc.Invocation invocation)
throws org.apache.dubbo.rpc.RpcException {
Result.CompatibleResult result = (Result.CompatibleResult) invoke(new Invoker.CompatibleInvoker<>(invoker),
new Invocation.CompatibleInvocation(invocation));
return result.getDelegate();
}
}
```

可以看到,default方法里,对参数进行了包装,然后调用老的invoke方法,并将返回值进行解包后返回给Dubbo框架。这里Result.CompatibleResult、Invocation.CompatibleInvocation以及Invoker.CompatibleInvoker都用到了代理模式。

感兴趣的同学可以详细看一下以下几个类:

* com.alibaba.dubbo.rpc.Invocation
* com.alibaba.dubbo.rpc.Invoker
* com.alibaba.dubbo.rpc.Result

## 后续todo list

目前兼容包仅仅是对常见的API及SPI做了支持,列表如下:

* com.alibaba.dubbo.rpc.Filter / Invocation / Invoker / Result / RpcContext / RpcException
* com.alibaba.dubbo.config.*Config
* com.alibaba.dubbo.config.annotation.Reference / Service
* com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo
* com.alibaba.dubbo.common.Constants / URL
* com.alibaba.dubbo.common.extension.ExtensionFactory
* com.alibaba.dubbo.common.serialize.Serialization / ObjectInput / ObjectOutput
* com.alibaba.dubbo.cache.CacheFactory / Cache
* com.alibaba.dubbo.rpc.service.EchoService / GenericService

大家如果在试用的过程中发现有任何问题请及时提出;同时如果对其他扩展点有兼容需求,也请大家提出来,也非常欢迎大家自己解决并贡献出来。
2 changes: 1 addition & 1 deletion blog/zh-cn/dubbo-contribue-to-opensource.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 本文将会以 incubator-dubbo 项目为例向你阐释,给开
---

# 以Dubbo为例,聊聊如何向开源项目做贡献
---


Github 上有众多优秀的开源项目,大多数 IT 从业者将其当做了予取予求的工具库,遇到什么需求,先去 Github 搜一把,但有没有想过有一天自己也可以给开源事业做一些贡献呢?本文将会以 incubator-dubbo 项目为例,向你阐释,给开源项目做贡献并不是一件难事。

Expand Down
4 changes: 2 additions & 2 deletions blog/zh-cn/dubbo-meetup-chengdu.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ keywords: Dubbo, 成都, meetup
description: 第四届Dubbo开发者沙龙将于8月26日在成都举行。
---

第四届Dubbo开发者沙龙将于8月26日在成都举行
---
# 第四届Dubbo开发者沙龙将于8月26日在成都举行


Aliware Open Source•成都站-Apache Dubbo开发者沙龙将于8月26日(周日)在成都高新区天府五街200号菁蓉国际广场8号楼2楼会议厅举办,技术GG们的思想盛宴,干货与福利一个都不会少。

Expand Down
4 changes: 2 additions & 2 deletions blog/zh-cn/dubbo-meetup-shanghai-jun-23rd-2018.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
第二届Dubbo开发者沙龙在上海成功举办
---
# 第二届Dubbo开发者沙龙在上海成功举办


第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+

Expand Down
4 changes: 2 additions & 2 deletions blog/zh-cn/dubbo-meetup-shenzhen.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
第三届Dubbo开发者沙龙在深圳成功举办
---
# 第三届Dubbo开发者沙龙在深圳成功举办


第三届Dubbo开发者沙龙在深圳成功举办,超过2000位开发者报名,现场参与人数700+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数17000+

Expand Down
1 change: 0 additions & 1 deletion blog/zh-cn/introduction-to-dubbo-spi.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ description: 本文介绍了Dubbo框架的核心,SPI扩展机制。
---

# Dubbo可扩展机制实战
---

## 1. Dubbo的扩展机制
在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。
Expand Down
1 change: 0 additions & 1 deletion blog/zh-cn/optimization-branch-prediction.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ title: 提前if判断帮助CPU分支预测
---

# 优化技巧:提前if判断帮助CPU分支预测
---

## 分支预测

Expand Down
2 changes: 1 addition & 1 deletion build/blog.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions site_config/blog.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ export default {
barText: '博客',
postsTitle: '所有文章',
list: [
{
title: 'Dubbo 2.7.x repackage后的兼容实现方案',
author:'@jerrick',
dateStr: 'Sep 4th, 2018',
desc: '本文简单描述了2.7.x repackage后对老版本的兼容性实现方案。',
link: '/zh-cn/blog/dubbo-compatible.html',
},
{
title: 'Dubbo与Kubernetes集成',
author:'@kongming',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
<link rel="stylesheet" href="/build/blogDetail.css" />
</head>
<body>
<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-1082635303"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-toggle" src="/img/menu_gray.png" data-reactid="8"/><ul data-reactid="9"><li class="menu-item menu-item-normal" data-reactid="10"><a href="/zh-cn/index.html" data-reactid="11">首页</a></li><li class="menu-item menu-item-normal" data-reactid="12"><a href="/zh-cn/docs/user/quick-start.html" data-reactid="13">文档</a></li><li class="menu-item menu-item-normal menu-item-normal-active" data-reactid="14"><a href="/zh-cn/blog/index.html" data-reactid="15">博客</a></li><li class="menu-item menu-item-normal" data-reactid="16"><a href="/zh-cn/community/index.html" data-reactid="17">社区</a></li></ul></div></div></header><section class="blog-content markdown-body" data-reactid="18"><h1>Dubbo基本用法之Provider配置</h1>
<hr>
<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-188396933"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-toggle" src="/img/menu_gray.png" data-reactid="8"/><ul data-reactid="9"><li class="menu-item menu-item-normal" data-reactid="10"><a href="/zh-cn/index.html" data-reactid="11">首页</a></li><li class="menu-item menu-item-normal" data-reactid="12"><a href="/zh-cn/docs/user/quick-start.html" data-reactid="13">文档</a></li><li class="menu-item menu-item-normal menu-item-normal-active" data-reactid="14"><a href="/zh-cn/blog/index.html" data-reactid="15">博客</a></li><li class="menu-item menu-item-normal" data-reactid="16"><a href="/zh-cn/community/index.html" data-reactid="17">社区</a></li></ul></div></div></header><section class="blog-content markdown-body" data-reactid="18"><h1>Dubbo基本用法之Provider配置</h1>
<h2>Dubbo基本用法</h2>
<p>本章节主要讲述如何配置dubbo,按照配置方式上分,可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。
按照功能角度进行划分,可以分为Dubbo Provider和Dubbo Consumer。接下来章节中,分别对dubbo provider和Dubbo consumer进行讲解。</p>
Expand Down
Loading

0 comments on commit 469b327

Please sign in to comment.