diff --git a/pom.xml b/pom.xml
index bffa398fa..5ad92ead7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,7 @@
spring-cloud-alibaba-dependenciesspring-cloud-alibaba-sentinelspring-cloud-alibaba-sentinel-datasource
+ spring-cloud-alibaba-sentinel-zuulspring-cloud-alibaba-nacos-configspring-cloud-alibaba-nacos-discoveryspring-cloud-alibaba-fescar
diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml
index 73f35e858..f4a78d751 100644
--- a/spring-cloud-alibaba-dependencies/pom.xml
+++ b/spring-cloud-alibaba-dependencies/pom.xml
@@ -20,7 +20,7 @@
1.4.23.1.00.1.3
- 0.8.1
+ 0.8.20.8.01.0.81.0.1
@@ -148,6 +148,11 @@
sentinel-web-servlet${sentinel.version}
+
+ com.alibaba.csp
+ sentinel-zuul-adapter
+ ${sentinel.version}
+ com.alibaba.cspsentinel-transport-simple-http
@@ -203,22 +208,6 @@
${fescar.version}
-
-
- com.aliyun.oss
- aliyun-sdk-oss
- ${oss.version}
-
-
-
-
- com.alibaba
- dubbo-dependencies-bom
- ${dubbo.version}
- pom
- import
-
-
com.alibaba
@@ -254,6 +243,13 @@
${dubbo-registry-nacos.version}
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ ${oss.version}
+
+
org.springframework.cloud
@@ -265,6 +261,11 @@
spring-cloud-alibaba-sentinel-datasource${project.version}
+
+ org.springframework.cloud
+ spring-cloud-alibaba-sentinel-zuul
+ ${project.version}
+ org.springframework.cloudspring-cloud-alicloud-oss
@@ -453,4 +454,4 @@
-
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc
index db4f43183..d5cc93a64 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc
@@ -6,7 +6,7 @@ Spring Cloud AliCloud ACM 是 Config Server 和 Client 的替代方案,客户
=== 如何引入 Spring Cloud AliCloud ACM
-Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先导入依赖管理POM。
+Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先导入依赖管理 POM。
[source,xml]
----
@@ -23,7 +23,7 @@ Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先
----
-接下来引入 Spring Cloud AliCloud ACM Starter 即可。
+并引入 Spring Cloud AliCloud ACM Starter 依赖。
[source,xml]
----
@@ -53,7 +53,7 @@ public class ProviderApplication {
}
----
-既然需要从配置中心服务端获取配置信息,那么肯定需要配置服务端的地址,在 bootstrap.properties 中,还需要配置上以下信息。
+在从配置中心服务端获取配置信息之前,还需要配置服务端的地址,在 bootstrap.properties 中,还需要配置以下信息。
[source,properties]
----
@@ -68,18 +68,18 @@ spring.cloud.alicloud.acm.server-port=8080
NOTE: 此时没有启动配置中心,启动应用会报错,因此在应用启动之前,应当首先启动配置中心。
-=== 启动配置中心
+==== 启动配置中心
-ACM 使用的配置中心有两种,一种是完全免费的轻量版配置中心,主要用于开发和本地调试,一种是云上配置中心ACM。通常情况下,可以使用轻量版配置中心作为开发和测试环境,使用云上的 ACM 作为灰度和生产环境。
+ACM 使用的配置中心有两种,一种是本地运行的轻量版配置中心,主要用于开发和本地调试,一种是阿里云产品 ACM。通常情况下,可以使用轻量版配置中心作为开发和测试环境,使用云上的 ACM 作为灰度和生产环境。
-==== 启动轻量版配置中心
+===== 使用轻量版配置中心
-轻量版配置中心的下载和启动方式可参考 https://help.aliyun.com/document_detail/44163.html?spm=a2c4g.11186623.6.677.5f206b82Z2mTCF[这里]
+轻量版配置中心的下载和启动方式可参考 https://help.aliyun.com/document_detail/44163.html[这里]
-NOTE: 只需要进行第1步(下载轻量配置中心)和第2步(启动轻量配置中心)即可,第3步(配置hosts)在与 ACM 结合使用时,不需要操作。
+NOTE: 只需要执行文档中的第1步 (下载轻量配置中心) 和第2步 (启动轻量配置中心)。
-==== 使用云上配置中心
+===== 使用阿里云配置中心
使用云上 ACM ,可以省去服务端的维护工作,同时稳定性也会更有保障。当使用云上配置中心时,代码部分和使用轻量配置中心并没有区别,但是配置上会有一些区别。
@@ -88,7 +88,7 @@ NOTE: 只需要进行第1步(下载轻量配置中心)和第2步(启动轻
[source,properties]
----
# 应用名会被作为从服务端获取配置 key 的关键词组成部分,因此是必选
-spring.application.name=ans-provider
+spring.application.name=acm-config
# 端口配置自由配置即可
server.port=18081
# 以下就是配置中心的IP和端口配置
@@ -99,9 +99,9 @@ spring.cloud.alicloud.acm.endpoint=acm.aliyun.com
spring.cloud.alicloud.acm.namespace=你的 ACM namespace,需要在 ACM 控制台查询
----
-NOTE: EDAS 提供应用托管服务,如果你将应用托管到 EDAS,那么 EDAS 将会自动为你填充所有配置。
+NOTE: EDAS 提供应用托管服务,如果你将应用托管到 EDAS,那么 EDAS 将会自动为你填充所有与业务无关的配置。
-=== 在配置中心添加配置
+==== 在配置中心添加配置
1. 启动好轻量版配置中心之后,在控制台中添加如下的配置。
@@ -115,9 +115,9 @@ Content: user.name=james
user.age=18
----
-NOTE: DataId 的格式为 `{prefix}. {file-extension}`,prefix 默认从配置 spring.application.name 中取值,file-extension 默认的值为 "properties"。
+NOTE: DataId 的格式为 `{prefix}.{file-extension}`,prefix 默认从配置 spring.application.name 中取值,file-extension 默认的值为 "properties"。
-=== 启动应用验证
+==== 启动应用验证
启动这个Example,可以在控制台看到打印出的值正是我们在轻量版配置中心上预先配置的值。
@@ -133,16 +133,16 @@ spring-cloud-starter-alicloud-acm 中 DataId 默认的文件扩展名是 propert
NOTE: 修改文件扩展名后,在配置中心中的 DataID 以及 Content 的格式都必须做相应的修改。
-=== 支持配置的动态更新
+=== 动态更新
-spring-cloud-starter-alicloud-acm 默认支持配置的动态更新,当您在配置中心修改配置的内容时,会触发 Spring 中的 Context Refresh 动作。
+spring-cloud-starter-alicloud-acm 默认支持配置的动态更新,当您在配置中心修改配置的内容时,会发布 Spring 中的 RefreshEvent 事件。
带有 @RefreshScope 和 @ConfigurationProperties 注解的类会自动刷新。
-NOTE: 你可以通过配置 spring.cloud.alicloud.acm.refresh.enabled=false 来关闭动态刷新
+NOTE: 你可以通过配置 spring.cloud.alicloud.acm.refresh.enabled=false 来关闭动态刷新。
-=== profile 粒度的配置
+=== Profile 粒度的配置
-spring-cloud-starter-alicloud-acm 在加载配置的时候,首先会尝试去加载 dataid 为{spring.application.name}.{file-extension}的配置,当设置了 spring.profiles.active 中配置有内容时,还会尝试依次去加载 spring.profile 对应的内容, dataid 的格式为{spring.application.name}-{profile}.{file-extension}的配置,且后者的优先级高于前者。
+spring-cloud-starter-alicloud-acm 在加载配置的时候,首先会加载 DataId 为{spring.application.name}.{file-extension}的配置,当 spring.profiles.active 中配置有内容时,还会依次去加载 spring.profile 对应的内容, DataId 的格式为{spring.application.name}-{profile}.{file-extension}的配置,且后者的优先级高于前者。
spring.profiles.active 属于配置的元数据,所以也必须配置在 bootstrap.properties 或 bootstrap.yaml 中。比如可以在 bootstrap.properties 中增加如下内容。
@@ -154,8 +154,11 @@ spring.profiles.active={profile-name}
Note: 也可以通过 JVM 参数 -Dspring.profiles.active=develop 或者 --spring.profiles.active=develop 这类优先级更高的方式来配置,只需遵循 Spring Boot 规范即可。
+=== 自定义配置中心超时时间
+
+ACM Client 与 Server 通信的超时时间默认是 3000ms,可以通过 `spring.cloud.alicloud.acm.timeout` 来修改超时时间,单位为 ms 。
-=== 支持自定义 Group 的配置
+=== 自定义 Group 的配置
在没有明确指定 `{spring.cloud.alicloud.acm.group}` 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:
@@ -164,9 +167,9 @@ Note: 也可以通过 JVM 参数 -Dspring.profiles.active=develop 或者 --sprin
spring.cloud.alicloud.acm.group=DEVELOP_GROUP
----
-NOTE: 该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 `spring.cloud.alicloud.acm.group` 的配置值一致。
+NOTE: 该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值要和 `spring.cloud.alicloud.acm.group` 的配置值一致。
-==== 支持共享配置
+=== 共享配置
ACM 提供了一种多个应用之间共享配置中心的同一个配置的推荐方式,供多个应用共享一些配置时使用,您在使用的时候需要添加在 bootstrap 中添加一个配置项 `spring.application.group`。
@@ -175,11 +178,14 @@ ACM 提供了一种多个应用之间共享配置中心的同一个配置的推
spring.application.group=company.department.team
----
-这时你的应用在获取之前提到的自身所独有的配置之前,会先依次从这些 DataId 去获取,分别是 company:application.properties, company.department:application.properties, company.department.team:application.properties。
-然后,还会从 {spring.application.group}:{spring.application.name}.{file-extension} 中获取
-越往后优先级越高,最高的仍然是应用自身所独有的配置。
+这时应用在获取上文提到的自身所独有的配置之前,会先依次从这些 DataId 去获取,分别是 company:application.properties, company.department:application.properties, company.department.team:application.properties。
+然后,还会从 {spring.application.group}:{spring.application.name}.{file-extension} 中获取,越往后优先级越高,最高的仍然是应用自身所独有的配置。
NOTE: 共享配置中 DataId 默认后缀为 properties,可以通过 spring.cloud.alicloud.acm.file-extension 配置. `{spring.application.group}:{spring.application.name}.{file-extension}` 。
NOTE: 如果设置了 `spring.profiles.active` ,DataId 的格式还支持 `{spring.application.group}:{spring.application.name}-{spring.profiles.active}.{file-extension}`。优先级高于 `{spring.application.group}:{spring.application.name}.{file-extension}`
+
+=== Actuator 监控
+
+ACM 对应的 Actuator 监控地址为 `/acm`,其中 config 代表了 ACM 元数据配置的信息,`runtime.sources` 对应的是从 ACM 服务端获取的配置的信息及最后刷新时间, `runtime.refreshHistory` 对应的是动态刷新的历史记录。
\ No newline at end of file
diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc
index bd88310af..57b3a6564 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc
@@ -261,9 +261,9 @@ public class NacosConsumerApp {
public String echoAppName(){
//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
- String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
- System.out.println("request url:"+url);
- return restTemplate.getForObject(url,String.class);
+ String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
+ System.out.println("request path:"+path);
+ return restTemplate.getForObject(path,String.class);
}
}
diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/acm.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/acm.adoc
index 0e823577d..41fdef33b 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc/acm.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc/acm.adoc
@@ -6,7 +6,7 @@ Spring Cloud Alibaba Cloud ACM is an alternative solution for Config Server and
=== How to Introduce Spring Cloud Alibaba Cloud ACM
-We’ve released Spring Cloud Alibaba version 0.2.1. You will need to add dependency management POM first.
+We’ve released Spring Cloud Alibaba version 0.2.2.BUILD-SNAPSHOT. You will need to add dependency management POM first.
[source,xml]
----
@@ -68,18 +68,18 @@ spring.cloud.alicloud.acm.server-port=8080
NOTE: By now the configuration center is not started yet, so you will get an error message if your application is started. Therefore, start the configuration center before you start your application.
-=== Start Configuration Center
+==== Start Configuration Center
-ACM uses two types of configuration centers. One is a lightweight configuration center which is totally free, the other is ACM which is used on Alibaba Cloud. Generally, you can use the lightweight version for application development and local testing, and use ACM for canary deployment or production.
+ACM uses two types of configuration centers. One is lightweight configuration center, the other is ACM which is used on Alibaba Cloud. Generally, you can use the lightweight version for application development and local testing, and use ACM for canary deployment or production.
-==== Start Lightweight Configuration Center
+===== Use Lightweight Configuration Center
Refer to the https://help.aliyun.com/document_detail/44163.html[Configure Lightweight Configuration Center] for details about how to download and install lightweight configuration center.
-NOTE: You only need to perform step 1(Download lightweight configuration center) and step 2(Start lightweight configuration center). Step 3(Configure hosts) is not required if you use ACM at the same time.
+NOTE: You only need to perform step 1(Download lightweight configuration center) and step 2(Start lightweight configuration center).
-==== Use ACM on the Cloud
+===== Use ACM on the Alibaba Cloud
Using ACM on the cloud saves you from the tedious work of server maintenance while at the same time provides a better stability. There is no difference at the code level between using ACM on cloud and lightweight configuration center, but there are some differences in configurations.
@@ -88,7 +88,7 @@ The following is a simple sample of using ACM. You can view configuration detail
[source,properties]
----
# The application name will be used as part of the keyword to obtain configuration key from the server, and is mandatory.
-spring.application.name=ans-provider
+spring.application.name=acm-config
# Configure your own port number
server.port=18081
# The following is the IP and port number of the configuration center.
@@ -99,9 +99,9 @@ spring.cloud.alicloud.acm.endpoint=acm.aliyun.com
spring.cloud.alicloud.acm.namespace=Your ACM namespace(You can find the namespace on the ACM console)
----
-NOTE: EDAS provides application hosting service and will fill in all configurations automatically for the hosted applications.
+NOTE: EDAS provides application hosting service and will fill in all configurations about ACM automatically for the hosted applications.
-=== Add Configuration in the Configuration Center
+==== Add Configuration in the Configuration Center
1. After you start the lightweight configuration center, add the following configuration on the console.
@@ -117,7 +117,7 @@ Content: user.name=james
NOTE: The format of dataId is `{prefix}. {file-extension}`. “prefix” is obtained from spring.application.name by default, and the value of “file-extension” is "properties” by default.
-=== Start Application Verification
+==== Start Application Verification
Start the following example and you can see that the value printed on the console is the value we configured in the lightweight configuration center.
@@ -133,16 +133,16 @@ You can set the file extension using spring.cloud.alicloud.acm.file-extension. J
NOTE: After you change the file extension, you need to make corresponding format changes in the DataID and content of the configuration center.
-=== Dynamic Configuration Updates
+=== Dynamic Configuration Refresh
-spring-cloud-starter-alicloud-acm supports dynamic configuration updates. Context Refresh in Spring is triggered when you update configuration in the configuration center.
-All classes with @RefreshScope and @ConfigurationProperties annotations will be refershed automatically.
+spring-cloud-starter-alicloud-acm supports dynamic configuration updates. RefreshEvent in Spring is published when you update configuration in the configuration center.
+All classes with @RefreshScope and @ConfigurationProperties annotations will be refreshed automatically.
NOTE: You can disable automatic refresh by this setting: spring.cloud.alicloud.acm.refresh.enabled=false
=== Configure Profile Granularity
-When configuration is loaded by spring-cloud-starter-alicloud-acm, configuration with dataid {spring.application.name}. {file-extension} will be loaded first. If there is content in spring.profiles.active, the content of spring.profile, and configuration with the dataid format of{spring.application.name}-{profile}. {file-extension} will also be loaded in turn, and the latter has higher priority.
+When configuration is loaded by spring-cloud-starter-alicloud-acm, configuration with DataId {spring.application.name}. {file-extension} will be loaded first. If there is content in spring.profiles.active, the content of spring.profile, and configuration with the dataid format of{spring.application.name}-{profile}. {file-extension} will also be loaded in turn, and the latter has higher priority.
spring.profiles.active is the configuration metadata, and should also be configured in bootstrap.properties or bootstrap.yaml. For example, you can add the following content in bootstrap.properties.
@@ -154,6 +154,10 @@ spring.profiles.active={profile-name}
Note: You can also configure the granularity through JVM parameters such as -Dspring.profiles.active=develop or --spring.profiles.active=develop, which have higher priority. Just follow the specifications of Spring Boot.
+=== Support Custom ACM Timeout
+
+the default timeout of ACM client get config from sever is 3000 ms . If you need to define a timeout, set configuration `spring.cloud.alicloud.acm.timeout`,the unit is millisecond.
+
=== Support Custom Group Configurations
@@ -183,3 +187,7 @@ The later in order, the higer the priority, and the unique configuration of the
NOTE: The default suffix of DataId is properties, and you can change it using spring.cloud.alicloud.acm.file-extension. `{spring.application.group}: {spring.application.name}. {file-extension}` 。
NOTE: If you configured `spring.profiles.active` , then the DataId format of `{spring.application.group}: {spring.application.name}-{spring.profiles.active}. {file-extension}` is also supported, and has higher priority than `{spring.application.group}: {spring.application.name}. {file-extension}`
+
+=== Actuator Endpoint
+
+the Actuator endpoint of ACM is `/acm`, `config` represents the ACM metadata configuration information, `runtime.sources` corresponds to the configuration information obtained from the ACM server and the last refresh time, `runtime.refreshHistory` corresponds to the dynamic refresh history.
\ No newline at end of file
diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/dependency-management.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/dependency-management.adoc
index 07b4dd403..ac027a633 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc/dependency-management.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc/dependency-management.adoc
@@ -29,7 +29,7 @@ If you want to use the latest BUILD-SNAPSHOT version, add Spring Snapshot Reposi
spring-snapshotSpring Snapshot Repository
- https://repo.spring.io/snapshot
+ https://repo.spring.io/snapshottrue
diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc
index 44f2222f5..21f0b144c 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc
@@ -261,9 +261,9 @@ public class NacosConsumerApp {
public String echoAppName(){
//Access through the combination of LoadBalanceClient and RestTemolate
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
- String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
- System.out.println("request url:" +url);
- return restTemplate.getForObject(url,String.class);
+ String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
+ System.out.println("request path:" +path);
+ return restTemplate.getForObject(path,String.class);
}
}
diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml
index 94467a24a..61ccc4718 100644
--- a/spring-cloud-alibaba-dubbo/pom.xml
+++ b/spring-cloud-alibaba-dubbo/pom.xml
@@ -3,8 +3,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- spring-cloud-alibabaorg.springframework.cloud
+ spring-cloud-alibaba0.2.2.BUILD-SNAPSHOT../pom.xml
@@ -13,6 +13,37 @@
spring-cloud-alibaba-dubboSpring Cloud Alibaba Dubbo
+
+ 2.6.5
+ 0.2.1.RELEASE
+ 0.0.2
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+ com.alibaba
+ dubbo-dependencies-bom
+ ${dubbo.version}
+ pom
+ import
+
+
+
+
+
+
@@ -170,9 +201,9 @@
-
-
-
+
+
+
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/annotation/DubboTransported.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/annotation/DubboTransported.java
new file mode 100644
index 000000000..2714923d0
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/annotation/DubboTransported.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.annotation;
+
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.client.RestTemplate;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * {@link DubboTransported @DubboTransported} annotation indicates that the traditional Spring Cloud Service-to-Service call is transported
+ * by Dubbo under the hood, there are two main scenarios:
+ *
+ *
+ * If {@link DubboTransported @DubboTransported} annotated classes, the invocation of all methods of
+ * {@link FeignClient @FeignClient} annotated classes.
+ *
+ *
+ * If {@link DubboTransported @DubboTransported} annotated methods of {@link FeignClient @FeignClient} annotated classes.
+ *
+ *
+ *
{@link LoadBalanced @LoadBalanced} {@link RestTemplate} annotated field, method and parameters
+ *
+ *
+ *
+ * @see FeignClient
+ * @see LoadBalanced
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
+@Documented
+public @interface DubboTransported {
+
+ /**
+ * The protocol of Dubbo transport whose value could be used the placeholder "dubbo.transport.protocol"
+ *
+ * @return the default protocol is "dubbo"
+ */
+ String protocol() default "${dubbo.transport.protocol:dubbo}";
+
+ /**
+ * The cluster of Dubbo transport whose value could be used the placeholder "dubbo.transport.cluster"
+ *
+ * @return the default cluster is "failover"
+ */
+ String cluster() default "${dubbo.transport.cluster:failover}";
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java
new file mode 100644
index 000000000..15eb6cf33
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.autoconfigure;
+
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;
+import org.springframework.cloud.alibaba.dubbo.client.loadbalancer.DubboMetadataInitializerInterceptor;
+import org.springframework.cloud.alibaba.dubbo.client.loadbalancer.DubboTransporterInterceptor;
+import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
+import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.MethodMetadata;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Dubbo Auto-{@link Configuration} for {@link LoadBalanced @LoadBalanced} {@link RestTemplate}
+ *
+ * @author Mercy
+ */
+@Configuration
+@ConditionalOnClass(RestTemplate.class)
+@AutoConfigureAfter(LoadBalancerAutoConfiguration.class)
+public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClassLoaderAware {
+
+ private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class;
+
+ private static final String DUBBO_TRANSPORTED_CLASS_NAME = DUBBO_TRANSPORTED_CLASS.getName();
+
+ @Autowired
+ private DubboServiceMetadataRepository repository;
+
+ @Autowired
+ private LoadBalancerInterceptor loadBalancerInterceptor;
+
+ @Autowired
+ private ConfigurableListableBeanFactory beanFactory;
+
+ @Autowired
+ private DubboGenericServiceFactory serviceFactory;
+
+ @Autowired
+ private DubboGenericServiceExecutionContextFactory contextFactory;
+
+ @Autowired
+ private Environment environment;
+
+ @LoadBalanced
+ @Autowired(required = false)
+ private Map restTemplates = Collections.emptyMap();
+
+ private ClassLoader classLoader;
+
+ /**
+ * Adapt the {@link RestTemplate} beans that are annotated {@link LoadBalanced @LoadBalanced} and
+ * {@link LoadBalanced @LoadBalanced} when Spring Boot application started
+ * (after the callback of {@link SmartInitializingSingleton} beans or
+ * {@link RestTemplateCustomizer#customize(RestTemplate) customization})
+ */
+ @EventListener(ApplicationStartedEvent.class)
+ public void adaptRestTemplates() {
+ for (Map.Entry entry : restTemplates.entrySet()) {
+ String beanName = entry.getKey();
+ Map dubboTranslatedAttributes = getDubboTranslatedAttributes(beanName);
+ if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) {
+ adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes);
+ }
+ }
+ }
+
+ /**
+ * Gets the annotation attributes {@link RestTemplate} bean being annotated
+ * {@link DubboTransported @DubboTransported}
+ *
+ * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} {@link RestTemplate}
+ * @return non-null {@link Map}
+ */
+ private Map getDubboTranslatedAttributes(String beanName) {
+ Map attributes = Collections.emptyMap();
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ if (beanDefinition instanceof AnnotatedBeanDefinition) {
+ AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
+ MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
+ attributes = factoryMethodMetadata != null ?
+ factoryMethodMetadata.getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME) : Collections.emptyMap();
+ }
+ return attributes;
+ }
+
+
+ /**
+ * Adapt the instance of {@link DubboTransporterInterceptor} to the {@link LoadBalancerInterceptor} Bean.
+ *
+ * @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean
+ * @param dubboTranslatedAttributes the annotation dubboTranslatedAttributes {@link RestTemplate} bean being annotated
+ * {@link DubboTransported @DubboTransported}
+ */
+ private void adaptRestTemplate(RestTemplate restTemplate, Map dubboTranslatedAttributes) {
+
+ DubboTransportedMetadata dubboTransportedMetadata = buildDubboTransportedMetadata(dubboTranslatedAttributes);
+
+ List interceptors = new ArrayList<>(restTemplate.getInterceptors());
+
+ int index = interceptors.indexOf(loadBalancerInterceptor);
+
+ index = index < 0 ? 0 : index;
+
+ // Add ClientHttpRequestInterceptor instances before loadBalancerInterceptor
+ interceptors.add(index++, new DubboMetadataInitializerInterceptor(repository));
+
+ interceptors.add(index++, new DubboTransporterInterceptor(repository, restTemplate.getMessageConverters(),
+ classLoader, dubboTransportedMetadata, serviceFactory, contextFactory));
+
+ restTemplate.setInterceptors(interceptors);
+ }
+
+ private DubboTransportedMetadata buildDubboTransportedMetadata(Map dubboTranslatedAttributes) {
+ DubboTransportedMetadata dubboTransportedMetadata = new DubboTransportedMetadata();
+ String protocol = (String) dubboTranslatedAttributes.get("protocol");
+ String cluster = (String) dubboTranslatedAttributes.get("cluster");
+ // resolve placeholders
+ dubboTransportedMetadata.setProtocol(environment.resolvePlaceholders(protocol));
+ dubboTransportedMetadata.setCluster(environment.resolvePlaceholders(cluster));
+ return dubboTransportedMetadata;
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java
index cd4422c71..89a50578a 100644
--- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java
@@ -16,15 +16,22 @@
*/
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import com.alibaba.dubbo.config.ProtocolConfig;
+import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
-import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
-import org.springframework.cloud.alibaba.dubbo.metadata.service.NacosMetadataConfigService;
-import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import java.util.Collection;
+import java.util.Iterator;
+
+import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL;
+
/**
* Spring Boot Auto-Configuration class for Dubbo Metadata
*
@@ -32,12 +39,39 @@ import org.springframework.context.annotation.Import;
*/
@Configuration
@Import(DubboServiceMetadataRepository.class)
+@DubboComponentScan(basePackages = "org.springframework.cloud.alibaba.dubbo.service")
public class DubboMetadataAutoConfiguration {
- @Bean
- @ConditionalOnBean(NacosConfigProperties.class)
- public MetadataConfigService metadataConfigService() {
- return new NacosMetadataConfigService();
+ public static final String METADATA_PROTOCOL_BEAN_NAME = "metadata";
+
+ /**
+ * Build an alias Bean for {@link ProtocolConfig}
+ *
+ * @param protocols {@link ProtocolConfig} Beans
+ * @return {@link ProtocolConfig} bean
+ */
+ @Bean(name = METADATA_PROTOCOL_BEAN_NAME)
+ public ProtocolConfig protocolConfig(Collection protocols) {
+ ProtocolConfig protocolConfig = null;
+ for (ProtocolConfig protocol : protocols) {
+ String protocolName = protocol.getName();
+ if (DEFAULT_PROTOCOL.equals(protocolName)) {
+ protocolConfig = protocol;
+ break;
+ }
+ }
+
+ if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them
+ Iterator iterator = protocols.iterator();
+ protocolConfig = iterator.hasNext() ? iterator.next() : null;
+ }
+
+ return protocolConfig;
}
+ @Bean
+ @ConditionalOnMissingBean
+ public DubboMetadataConfigServiceProxy dubboMetadataConfigServiceProxy(DubboGenericServiceFactory factory) {
+ return new DubboMetadataConfigServiceProxy(factory);
+ }
}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java
index d37d8dc01..55d2f0a94 100644
--- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java
@@ -19,17 +19,19 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import feign.Contract;
import feign.Feign;
import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.cloud.alibaba.dubbo.metadata.resolver.FeignMetadataResolver;
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
-import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration;
-import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
/**
@@ -39,16 +41,22 @@ import org.springframework.context.annotation.Configuration;
*/
@ConditionalOnClass(value = Feign.class)
@AutoConfigureAfter(FeignAutoConfiguration.class)
-@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class)
@Configuration
public class DubboOpenFeignAutoConfiguration {
- @Value("${spring.application.name}")
- private String currentApplicationName;
-
@Bean
@ConditionalOnMissingBean
public MetadataResolver metadataJsonResolver(ObjectProvider contract) {
- return new FeignMetadataResolver(currentApplicationName, contract);
+ return new DubboServiceBeanMetadataResolver(contract);
}
+
+ @Bean
+ public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment,
+ DubboServiceMetadataRepository dubboServiceMetadataRepository,
+ DubboGenericServiceFactory dubboGenericServiceFactory,
+ DubboGenericServiceExecutionContextFactory contextFactory) {
+ return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository,
+ dubboGenericServiceFactory, contextFactory);
+ }
+
}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java
index 7c7aa9fde..be821e173 100644
--- a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestMetadataRegistrationAutoConfiguration.java
@@ -18,22 +18,18 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import com.alibaba.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
-import com.fasterxml.jackson.core.JsonProcessingException;
+
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
-import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
-import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
+import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
/**
* The Auto-Configuration class for Dubbo REST metadata registration,
* REST metadata that is a part of {@link Registration#getMetadata() Spring Cloud service instances' metadata}
@@ -42,45 +38,25 @@ import java.util.Set;
* @author Mercy
*/
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
-@ConditionalOnMissingBean(value = {
- MetadataResolver.class,
- MetadataConfigService.class
+@ConditionalOnBean(value = {
+ MetadataResolver.class
})
@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class})
@Configuration
public class DubboRestMetadataRegistrationAutoConfiguration {
- /**
- * A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
- * the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods.
- */
- private final Set serviceRestMetadata = new LinkedHashSet<>();
-
@Autowired
private MetadataResolver metadataResolver;
@Autowired
- private MetadataConfigService metadataConfigService;
+ private PublishingDubboMetadataConfigService dubboMetadataConfigService;
+
+ @Value("${spring.application.name:application}")
+ private String currentApplicationName;
@EventListener(ServiceBeanExportedEvent.class)
- public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
+ public void recordRestMetadata(ServiceBeanExportedEvent event) {
ServiceBean serviceBean = event.getServiceBean();
- serviceRestMetadata.addAll(metadataResolver.resolveServiceRestMetadata(serviceBean));
+ dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
}
-
- /**
- * Pre-handle Spring Cloud application service registered:
- *
- * Put restMetadata with the JSON format into
- * {@link Registration#getMetadata() service instances' metadata}
- *
- *
- * @param event {@link InstancePreRegisteredEvent} instance
- */
- @EventListener(InstancePreRegisteredEvent.class)
- public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
- Registration registration = event.getRegistration();
- metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), serviceRestMetadata);
- }
-
}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java
new file mode 100644
index 000000000..dc1ad2860
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceAutoConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.autoconfigure;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.alibaba.dubbo.service.parameter.PathVariableServiceParameterResolver;
+import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestBodyServiceParameterResolver;
+import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestHeaderServiceParameterResolver;
+import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestParamServiceParameterResolver;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * Spring Boot Auto-Configuration class for Dubbo Service
+ *
+ * @author Mercy
+ */
+@Configuration
+public class DubboServiceAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DubboGenericServiceFactory dubboGenericServiceFactory() {
+ return new DubboGenericServiceFactory();
+ }
+
+ @Configuration
+ @Import(value = {
+ DubboGenericServiceExecutionContextFactory.class,
+ RequestParamServiceParameterResolver.class,
+ RequestBodyServiceParameterResolver.class,
+ RequestHeaderServiceParameterResolver.class,
+ PathVariableServiceParameterResolver.class
+ })
+ static class ParameterResolversConfiguration {
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponse.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponse.java
new file mode 100644
index 000000000..25ba95a26
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponse.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
+
+import com.alibaba.dubbo.rpc.service.GenericException;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Dubbo {@link ClientHttpResponse} implementation
+ *
+ * @author Mercy
+ * @see DubboTransporterInterceptor
+ */
+class DubboClientHttpResponse implements ClientHttpResponse {
+
+ private final HttpStatus httpStatus;
+
+ private final String statusText;
+
+ private final HttpHeaders httpHeaders = new HttpHeaders();
+
+ private final DubboHttpOutputMessage httpOutputMessage;
+
+ public DubboClientHttpResponse(DubboHttpOutputMessage httpOutputMessage, GenericException exception) {
+ this.httpStatus = exception != null ? HttpStatus.INTERNAL_SERVER_ERROR : HttpStatus.OK;
+ this.statusText = exception != null ? exception.getExceptionMessage() : httpStatus.getReasonPhrase();
+ this.httpOutputMessage = httpOutputMessage;
+ this.httpHeaders.putAll(httpOutputMessage.getHeaders());
+ }
+
+ @Override
+ public HttpStatus getStatusCode() throws IOException {
+ return httpStatus;
+ }
+
+ @Override
+ public int getRawStatusCode() throws IOException {
+ return httpStatus.value();
+ }
+
+ @Override
+ public String getStatusText() throws IOException {
+ return statusText;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return httpOutputMessage.getBody().getInputStream();
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java
new file mode 100644
index 000000000..387cf6b17
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
+
+import com.alibaba.dubbo.rpc.service.GenericException;
+
+import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder;
+import org.springframework.cloud.alibaba.dubbo.http.util.HttpMessageConverterResolver;
+import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.converter.HttpMessageConverter;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Dubbo {@link ClientHttpResponse} Factory
+ *
+ * @author Mercy
+ */
+class DubboClientHttpResponseFactory {
+
+ private final HttpMessageConverterResolver httpMessageConverterResolver;
+
+ public DubboClientHttpResponseFactory(List> messageConverters, ClassLoader classLoader) {
+ this.httpMessageConverterResolver = new HttpMessageConverterResolver(messageConverters, classLoader);
+ }
+
+ public ClientHttpResponse build(Object result, GenericException exception,
+ RequestMetadata requestMetadata, RestMethodMetadata restMethodMetadata) {
+
+ DubboHttpOutputMessage httpOutputMessage = new DubboHttpOutputMessage();
+
+ HttpMessageConverterHolder httpMessageConverterHolder = httpMessageConverterResolver.resolve(requestMetadata, restMethodMetadata);
+
+ if (httpMessageConverterHolder != null) {
+ MediaType mediaType = httpMessageConverterHolder.getMediaType();
+ HttpMessageConverter converter = httpMessageConverterHolder.getConverter();
+ try {
+ converter.write(result, mediaType, httpOutputMessage);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return new DubboClientHttpResponse(httpOutputMessage, exception);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboHttpOutputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboHttpOutputMessage.java
new file mode 100644
index 000000000..1906aeb07
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboHttpOutputMessage.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.util.FastByteArrayOutputStream;
+
+import java.io.IOException;
+
+/**
+ * Dubbo {@link HttpOutputMessage} implementation
+ *
+ * @author Mercy
+ */
+class DubboHttpOutputMessage implements HttpOutputMessage {
+
+ private final FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream();
+
+ private final HttpHeaders httpHeaders = new HttpHeaders();
+
+ @Override
+ public FastByteArrayOutputStream getBody() throws IOException {
+ return outputStream;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java
new file mode 100644
index 000000000..de488e672
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
+
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * Dubbo Metadata {@link ClientHttpRequestInterceptor} Initializing Interceptor executes intercept before
+ * {@link DubboTransporterInterceptor}
+ *
+ * @author Mercy
+ */
+public class DubboMetadataInitializerInterceptor implements ClientHttpRequestInterceptor {
+
+ private final DubboServiceMetadataRepository repository;
+
+ public DubboMetadataInitializerInterceptor(DubboServiceMetadataRepository repository) {
+ this.repository = repository;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ URI originalUri = request.getURI();
+
+ String serviceName = originalUri.getHost();
+
+ repository.initialize(serviceName);
+
+ // Execute next
+ return execution.execute(request, body);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java
new file mode 100644
index 000000000..d7b9bb375
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/client/loadbalancer/DubboTransporterInterceptor.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
+
+import com.alibaba.dubbo.rpc.service.GenericException;
+import com.alibaba.dubbo.rpc.service.GenericService;
+
+import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest;
+import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.PathMatcher;
+import org.springframework.web.util.UriComponents;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.web.util.UriComponentsBuilder.fromUri;
+
+/**
+ * Dubbo Transporter {@link ClientHttpRequestInterceptor} implementation
+ *
+ * @author Mercy
+ * @see LoadBalancerInterceptor
+ */
+public class DubboTransporterInterceptor implements ClientHttpRequestInterceptor {
+
+ private final DubboServiceMetadataRepository repository;
+
+ private final DubboClientHttpResponseFactory clientHttpResponseFactory;
+
+ private final DubboTransportedMetadata dubboTransportedMetadata;
+
+ private final DubboGenericServiceFactory serviceFactory;
+
+ private final DubboGenericServiceExecutionContextFactory contextFactory;
+
+ private final PathMatcher pathMatcher = new AntPathMatcher();
+
+ public DubboTransporterInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository,
+ List> messageConverters,
+ ClassLoader classLoader,
+ DubboTransportedMetadata dubboTransportedMetadata,
+ DubboGenericServiceFactory serviceFactory,
+ DubboGenericServiceExecutionContextFactory contextFactory) {
+ this.repository = dubboServiceMetadataRepository;
+ this.dubboTransportedMetadata = dubboTransportedMetadata;
+ this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader);
+ this.serviceFactory = serviceFactory;
+ this.contextFactory = contextFactory;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ URI originalUri = request.getURI();
+
+ String serviceName = originalUri.getHost();
+
+ RequestMetadata clientMetadata = buildRequestMetadata(request);
+
+ DubboServiceMetadata dubboServiceMetadata = repository.get(serviceName, clientMetadata);
+
+ if (dubboServiceMetadata == null) {
+ // if DubboServiceMetadata is not found, executes next
+ return execution.execute(request, body);
+ }
+
+ RestMethodMetadata dubboRestMethodMetadata = dubboServiceMetadata.getRestMethodMetadata();
+
+ GenericService genericService = serviceFactory.create(dubboServiceMetadata, dubboTransportedMetadata);
+
+ MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(request, body);
+
+ customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata);
+
+ DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest);
+
+ Object result = null;
+ GenericException exception = null;
+
+ try {
+ result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters());
+ } catch (GenericException e) {
+ exception = e;
+ }
+
+ return clientHttpResponseFactory.build(result, exception, clientMetadata, dubboRestMethodMetadata);
+ }
+
+ protected void customizeRequest(MutableHttpServerRequest httpServerRequest,
+ RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) {
+
+ RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest();
+ String pathPattern = dubboRequestMetadata.getPath();
+
+ Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath());
+
+ if (!CollectionUtils.isEmpty(pathVariables)) {
+ // Put path variables Map into query parameters Map
+ httpServerRequest.params(pathVariables);
+ }
+
+ }
+
+ private RequestMetadata buildRequestMetadata(HttpRequest request) {
+ UriComponents uriComponents = fromUri(request.getURI()).build(true);
+ RequestMetadata requestMetadata = new RequestMetadata();
+ requestMetadata.setPath(uriComponents.getPath());
+ requestMetadata.setMethod(request.getMethod().name());
+ requestMetadata.setParams(uriComponents.getQueryParams());
+ requestMetadata.setHeaders(request.getHeaders());
+ return requestMetadata;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java
new file mode 100644
index 000000000..c74f2e992
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/ByteArrayHttpInputMessage.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http;
+
+import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Byte array {@link HttpInputMessage} implementation
+ *
+ * @author Mercy
+ */
+class ByteArrayHttpInputMessage implements HttpInputMessage {
+
+ private final HttpHeaders httpHeaders;
+
+ private final InputStream inputStream;
+
+ public ByteArrayHttpInputMessage(byte[] body) {
+ this(new HttpHeaders(), body);
+ }
+
+ public ByteArrayHttpInputMessage(HttpHeaders httpHeaders, byte[] body) {
+ this.httpHeaders = httpHeaders;
+ this.inputStream = new UnsafeByteArrayInputStream(body);
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return inputStream;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultHttpRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultHttpRequest.java
new file mode 100644
index 000000000..3f1f376db
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/DefaultHttpRequest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.web.util.UriComponentsBuilder.fromPath;
+
+/**
+ * Default {@link HttpRequest} implementation
+ *
+ * @author Mercy
+ */
+public class DefaultHttpRequest implements HttpRequest {
+
+ private final String method;
+
+ private final URI uri;
+
+ private final HttpHeaders headers = new HttpHeaders();
+
+ public DefaultHttpRequest(String method, String path, Map> params,
+ Map> headers) {
+ this.method = method == null ? HttpMethod.GET.name() : method.toUpperCase();
+ this.uri = buildURI(path, params);
+ this.headers.putAll(headers);
+ }
+
+ private URI buildURI(String path, Map> params) {
+ UriComponentsBuilder builder = fromPath(path)
+ .queryParams(new LinkedMultiValueMap<>(params));
+ return builder.build().toUri();
+ }
+
+ @Override
+ public HttpMethod getMethod() {
+ return HttpMethod.resolve(getMethodValue());
+ }
+
+ public String getMethodValue() {
+ return method;
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * {@link HttpRequest} Builder
+ */
+ public static class Builder {
+
+ String method;
+
+ String path;
+
+ MultiValueMap params = new LinkedMultiValueMap<>();
+
+ MultiValueMap headers = new LinkedMultiValueMap<>();
+
+ public Builder method(String method) {
+ this.method = method;
+ return this;
+ }
+
+ public Builder path(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public Builder param(String name, String value) {
+ this.params.add(name, value);
+ return this;
+ }
+
+ public Builder header(String name, String value) {
+ this.headers.add(name, value);
+ return this;
+ }
+
+ public Builder params(Map> params) {
+ this.params.putAll(params);
+ return this;
+ }
+
+ public Builder headers(Map> headers) {
+ this.headers.putAll(headers);
+ return this;
+ }
+
+ public HttpRequest build() {
+ return new DefaultHttpRequest(method, path, params, headers);
+ }
+ }
+
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/HttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/HttpServerRequest.java
new file mode 100644
index 000000000..f56a3f939
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/HttpServerRequest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http;
+
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.MultiValueMap;
+
+/**
+ * HTTP Server Request
+ *
+ * @author Mercy
+ */
+public interface HttpServerRequest extends HttpRequest, HttpInputMessage {
+
+ /**
+ * Return a path of current HTTP request
+ *
+ * @return
+ */
+ String getPath();
+
+ /**
+ * Return a map with parsed and decoded query parameter values.
+ */
+ MultiValueMap getQueryParams();
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/MutableHttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/MutableHttpServerRequest.java
new file mode 100644
index 000000000..62240f3b2
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/MutableHttpServerRequest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.MultiValueMap;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Map;
+
+import static org.springframework.cloud.alibaba.dubbo.http.util.HttpUtils.getParameters;
+
+/**
+ * Mutable {@link HttpServerRequest} implementation
+ *
+ * @author Mercy
+ */
+public class MutableHttpServerRequest implements HttpServerRequest {
+
+ private final HttpMethod httpMethod;
+
+ private final URI uri;
+
+ private final String path;
+
+ private final MultiValueMap queryParams;
+
+ private final HttpHeaders httpHeaders;
+
+ private final HttpInputMessage httpInputMessage;
+
+ public MutableHttpServerRequest(HttpRequest httpRequest, byte[] body) {
+ this.httpMethod = httpRequest.getMethod();
+ this.uri = httpRequest.getURI();
+ this.path = uri.getPath();
+ this.httpHeaders = httpRequest.getHeaders();
+ this.queryParams = getParameters(httpRequest);
+ this.httpInputMessage = new ByteArrayHttpInputMessage(body);
+ }
+
+ public MutableHttpServerRequest params(Map params) {
+ queryParams.setAll(params);
+ return this;
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return httpInputMessage.getBody();
+ }
+
+ @Override
+ public HttpMethod getMethod() {
+ return httpMethod;
+ }
+
+ // Override method since Spring Framework 5.0
+ public String getMethodValue() {
+ return httpMethod.name();
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public MultiValueMap getQueryParams() {
+ return queryParams;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/converter/HttpMessageConverterHolder.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/converter/HttpMessageConverterHolder.java
new file mode 100644
index 000000000..e0d7d11f3
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/converter/HttpMessageConverterHolder.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http.converter;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+
+/**
+ * {@link HttpMessageConverter} Holder with {@link MediaType}.
+ *
+ * @author Mercy
+ */
+public class HttpMessageConverterHolder {
+
+ private final MediaType mediaType;
+
+ private final HttpMessageConverter> converter;
+
+ public HttpMessageConverterHolder(MediaType mediaType, HttpMessageConverter> converter) {
+ this.mediaType = mediaType;
+ this.converter = converter;
+ }
+
+ public MediaType getMediaType() {
+ return mediaType;
+ }
+
+ public HttpMessageConverter> getConverter() {
+ return converter;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractHttpRequestMatcher.java
new file mode 100644
index 000000000..3e16664c6
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractHttpRequestMatcher.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http.matcher;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Abstract {@link HttpRequestMatcher} implementation
+ *
+ * @author Rossen Stoyanchev
+ * @author Mercy
+ */
+public abstract class AbstractHttpRequestMatcher implements HttpRequestMatcher {
+
+ /**
+ * Return the discrete items a request condition is composed of.
+ *
For example URL patterns, HTTP request methods, param expressions, etc.
+ *
+ * @return a collection of objects, never {@code null}
+ */
+ protected abstract Collection> getContent();
+
+ /**
+ * The notation to use when printing discrete items of content.
+ *
For example {@code " || "} for URL patterns or {@code " && "}
+ * for param expressions.
+ */
+ protected abstract String getToStringInfix();
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ return getContent().equals(((AbstractHttpRequestMatcher) other).getContent());
+ }
+
+ @Override
+ public int hashCode() {
+ return getContent().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[");
+ for (Iterator> iterator = getContent().iterator(); iterator.hasNext(); ) {
+ Object expression = iterator.next();
+ builder.append(expression.toString());
+ if (iterator.hasNext()) {
+ builder.append(getToStringInfix());
+ }
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractMediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractMediaTypeExpression.java
new file mode 100644
index 000000000..de5d9f841
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractMediaTypeExpression.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http.matcher;
+
+import org.springframework.http.MediaType;
+
+/**
+ * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractMediaTypeExpression
+ *
+ * @author Arjen Poutsma
+ * @author Rossen Stoyanchev
+ * @author Mercy
+ */
+public class AbstractMediaTypeExpression implements MediaTypeExpression, Comparable {
+
+ private final MediaType mediaType;
+
+ private final boolean negated;
+
+ AbstractMediaTypeExpression(String expression) {
+ if (expression.startsWith("!")) {
+ this.negated = true;
+ expression = expression.substring(1);
+ } else {
+ this.negated = false;
+ }
+ this.mediaType = MediaType.parseMediaType(expression);
+ }
+
+ AbstractMediaTypeExpression(MediaType mediaType, boolean negated) {
+ this.mediaType = mediaType;
+ this.negated = negated;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ return this.mediaType;
+ }
+
+ @Override
+ public boolean isNegated() {
+ return this.negated;
+ }
+
+
+ @Override
+ public int compareTo(AbstractMediaTypeExpression other) {
+ return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ AbstractMediaTypeExpression otherExpr = (AbstractMediaTypeExpression) other;
+ return (this.mediaType.equals(otherExpr.mediaType) && this.negated == otherExpr.negated);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.mediaType.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append(this.mediaType.toString());
+ return builder.toString();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractNameValueExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractNameValueExpression.java
new file mode 100644
index 000000000..695e67924
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/AbstractNameValueExpression.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http.matcher;
+
+import org.springframework.http.HttpRequest;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import static org.springframework.util.StringUtils.trimWhitespace;
+
+/**
+ * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression
+ *
+ * @author Rossen Stoyanchev
+ * @author Arjen Poutsma
+ * @author Mercy
+ */
+abstract class AbstractNameValueExpression implements NameValueExpression {
+
+ protected final String name;
+
+ protected final T value;
+
+ protected final boolean negated;
+
+ AbstractNameValueExpression(String expression) {
+ int separator = expression.indexOf('=');
+ if (separator == -1) {
+ this.negated = expression.startsWith("!");
+ this.name = trimWhitespace((this.negated ? expression.substring(1) : expression));
+ this.value = null;
+ } else {
+ this.negated = (separator > 0) && (expression.charAt(separator - 1) == '!');
+ this.name = trimWhitespace((this.negated ? expression.substring(0, separator - 1)
+ : expression.substring(0, separator)));
+ String valueExpression = getValueExpression(expression, separator);
+ this.value = isExcludedValue(valueExpression) ? null : parseValue(valueExpression);
+ }
+ }
+
+ private String getValueExpression(String expression, int separator) {
+ return trimWhitespace(expression.substring(separator + 1));
+ }
+
+ /**
+ * Exclude the pattern value Expression: "{value}", subclass could override this method.
+ *
+ * @param valueExpression
+ * @return
+ */
+ protected boolean isExcludedValue(String valueExpression) {
+ return StringUtils.hasText(valueExpression) &&
+ valueExpression.startsWith("{")
+ && valueExpression.endsWith("}");
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public T getValue() {
+ return this.value;
+ }
+
+ @Override
+ public boolean isNegated() {
+ return this.negated;
+ }
+
+ public final boolean match(HttpRequest request) {
+ boolean isMatch;
+ if (this.value != null) {
+ isMatch = matchValue(request);
+ } else {
+ isMatch = matchName(request);
+ }
+ return (this.negated ? !isMatch : isMatch);
+ }
+
+
+ protected abstract boolean isCaseSensitiveName();
+
+ protected abstract T parseValue(String valueExpression);
+
+ protected abstract boolean matchName(HttpRequest request);
+
+ protected abstract boolean matchValue(HttpRequest request);
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ AbstractNameValueExpression> that = (AbstractNameValueExpression>) other;
+ return ((isCaseSensitiveName() ? this.name.equals(that.name) : this.name.equalsIgnoreCase(that.name)) &&
+ ObjectUtils.nullSafeEquals(this.value, that.value) && this.negated == that.negated);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (isCaseSensitiveName() ? this.name.hashCode() : this.name.toLowerCase().hashCode());
+ result = 31 * result + (this.value != null ? this.value.hashCode() : 0);
+ result = 31 * result + (this.negated ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (this.value != null) {
+ builder.append(this.name);
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append('=');
+ builder.append(this.value);
+ } else {
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append(this.name);
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/CompositeHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/CompositeHttpRequestMatcher.java
new file mode 100644
index 000000000..181edf2b3
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/http/matcher/CompositeHttpRequestMatcher.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.http.matcher;
+
+import org.springframework.http.HttpRequest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Composite {@link HttpRequestMatcher} implementation
+ *
+ * @author Mercy
+ */
+public abstract class CompositeHttpRequestMatcher extends AbstractHttpRequestMatcher {
+
+ private final List matchers = new LinkedList<>();
+
+ public CompositeHttpRequestMatcher(HttpRequestMatcher... matchers) {
+ this.matchers.addAll(Arrays.asList(matchers));
+ }
+
+ public CompositeHttpRequestMatcher and(HttpRequestMatcher matcher) {
+ this.matchers.add(matcher);
+ return this;
+ }
+
+ @Override
+ public boolean match(HttpRequest request) {
+ for (HttpRequestMatcher matcher : matchers) {
+ if (!matcher.match(request)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected List getMatchers() {
+ return this.matchers;
+ }
+
+ @Override
+ protected Collection> getContent() {
+ List