This is an automated email from the ASF dual-hosted git repository.
wangxin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
The following commit(s) were added to refs/heads/master by this push:
new 667f227 [Dubbo-3886] Integrate with SOFARegistry. (#3886)
667f227 is described below
commit 667f2271b3c93f0c4f321368e32eb37a62d1fe0c
Author: Geng Zhang <[email protected]>
AuthorDate: Thu May 2 10:07:05 2019 +0800
[Dubbo-3886] Integrate with SOFARegistry. (#3886)
* Integrate with SOFARegistry.
---
dubbo-all/pom.xml | 8 +
dubbo-bom/pom.xml | 5 +
dubbo-dependencies-bom/pom.xml | 15 +-
dubbo-distribution/pom.xml | 5 +
dubbo-registry/dubbo-registry-sofa/pom.xml | 141 ++++++++++
.../apache/dubbo/registry/sofa/SofaRegistry.java | 292 +++++++++++++++++++++
.../dubbo/registry/sofa/SofaRegistryConstants.java | 43 +++
.../dubbo/registry/sofa/SofaRegistryFactory.java | 41 +++
.../org.apache.dubbo.registry.RegistryFactory | 1 +
.../apache/dubbo/registry/sofa/HelloService.java | 24 ++
.../dubbo/registry/sofa/HelloServiceImpl.java | 44 ++++
.../dubbo/registry/sofa/SofaRegistryTest.java | 148 +++++++++++
.../src/test/resources/log4j.properties | 7 +
dubbo-registry/pom.xml | 1 +
.../dubbo/rpc/protocol/thrift/ThriftCodec.java | 3 +-
15 files changed, 775 insertions(+), 3 deletions(-)
diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index e0e2366..08621e4 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -256,6 +256,13 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-sofa</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-monitor-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
@@ -530,6 +537,7 @@
<include>org.apache.dubbo:dubbo-registry-redis</include>
<include>org.apache.dubbo:dubbo-registry-consul</include>
<include>org.apache.dubbo:dubbo-registry-etcd3</include>
+
<include>org.apache.dubbo:dubbo-registry-sofa</include>
<include>org.apache.dubbo:dubbo-monitor-api</include>
<include>org.apache.dubbo:dubbo-monitor-default</include>
<include>org.apache.dubbo:dubbo-config-api</include>
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index e894f8b..148b49a 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -254,6 +254,11 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-sofa</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-monitor-api</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 2d8be67..6d68457 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -145,6 +145,7 @@
<spring_test_version>4.3.16.RELEASE</spring_test_version>
<metrics_version>2.0.1</metrics_version>
+ <sofa_registry_version>5.2.0</sofa_registry_version>
<gson_version>2.8.5</gson_version>
<jsonrpc_version>1.2.0</jsonrpc_version>
<portlet_version>2.0</portlet_version>
@@ -458,7 +459,6 @@
<version>${commons_lang3_version}</version>
</dependency>
-
<!-- for dubbo-rpc-webservice -->
<dependency>
<groupId>javax.xml.bind</groupId>
@@ -519,6 +519,19 @@
<artifactId>metrics-rest</artifactId>
<version>${metrics_version}</version>
</dependency>
+
+ <!-- for dubbo-registry-sofa -->
+ <dependency>
+ <groupId>com.alipay.sofa</groupId>
+ <artifactId>registry-client-all</artifactId>
+ <version>${sofa_registry_version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.alipay.sofa</groupId>
+ <artifactId>registry-test</artifactId>
+ <version>${sofa_registry_version}</version>
+ <scope>test</scope>
+ </dependency>
<!-- Test lib -->
<dependency>
diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml
index 50fd855..e92363d 100644
--- a/dubbo-distribution/pom.xml
+++ b/dubbo-distribution/pom.xml
@@ -182,6 +182,11 @@
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-sofa</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-monitor-api</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/dubbo-registry/dubbo-registry-sofa/pom.xml
b/dubbo-registry/dubbo-registry-sofa/pom.xml
new file mode 100644
index 0000000..7a2415f
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-sofa/pom.xml
@@ -0,0 +1,141 @@
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
+ <parent>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry</artifactId>
+ <version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-registry-sofa</artifactId>
+ <name>${project.artifactId}</name>
+ <description>The SOFARegistry module of Dubbo project</description>
+
+ <properties>
+ <javax.ws.rs.version>2.1</javax.ws.rs.version>
+ <argline>-Dnetwork_interface_denylist=docker0</argline>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-registry-api</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-common</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alipay.sofa</groupId>
+ <artifactId>registry-client-all</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.alipay.sofa</groupId>
+ <artifactId>sofa-common-tools</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Test Libraries -->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-config-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-rpc-dubbo</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-remoting-netty4</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- test modules -->
+ <dependency>
+ <groupId>com.alipay.sofa</groupId>
+ <artifactId>registry-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>log4j-over-slf4j</artifactId>
+ <groupId>org.slf4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>log4j-jcl</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>log4j-core</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>log4j-api</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-netty4</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ <version>${javax.ws.rs.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+</project>
\ No newline at end of file
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
new file mode 100644
index 0000000..a514d7a
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
@@ -0,0 +1,292 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.client.api.RegistryClient;
+import com.alipay.sofa.registry.client.api.RegistryClientConfig;
+import com.alipay.sofa.registry.client.api.Subscriber;
+import com.alipay.sofa.registry.client.api.model.RegistryType;
+import com.alipay.sofa.registry.client.api.model.UserData;
+import com.alipay.sofa.registry.client.api.registration.PublisherRegistration;
+import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration;
+import com.alipay.sofa.registry.client.provider.DefaultRegistryClient;
+import
com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder;
+import com.alipay.sofa.registry.core.model.ScopeEnum;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.registry.NotifyListener;
+import org.apache.dubbo.registry.support.FailbackRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static
org.apache.dubbo.registry.sofa.SofaRegistryConstants.ADDRESS_WAIT_TIME_KEY;
+import static
org.apache.dubbo.registry.sofa.SofaRegistryConstants.DEFAULT_GROUP;
+import static
org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_DATA_CENTER;
+import static
org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_REGION;
+
+/**
+ * The Sofa registry.
+ *
+ * @since 2.7.2
+ */
+public class SofaRegistry extends FailbackRegistry {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(SofaRegistry.class);
+
+ /**
+ * Cache subscriber by dataId
+ */
+ private final Map<String, Subscriber> subscribers = new
ConcurrentHashMap<>();
+
+ /**
+ * Direct registry client
+ */
+ private RegistryClient registryClient;
+ /**
+ * wait address from registry
+ */
+ private int waitAddressTimeout;
+
+ /**
+ * Instantiates a new Sofa registry.
+ *
+ * @param url the url
+ */
+ public SofaRegistry(URL url) {
+ super(url);
+ if (LOGGER.isInfoEnabled()) {
+ LOGGER.info("Build sofa registry by url:" + url);
+ }
+ this.registryClient = buildClient(url);
+ this.waitAddressTimeout =
Integer.parseInt(ConfigUtils.getProperty(ADDRESS_WAIT_TIME_KEY, "5000"));
+ }
+
+ /**
+ * Build client registry client.
+ *
+ * @param url the url
+ * @return the registry client
+ */
+ protected RegistryClient buildClient(URL url) {
+ RegistryClientConfig config =
DefaultRegistryClientConfigBuilder.start()
+ .setDataCenter(LOCAL_DATA_CENTER)
+ .setZone(LOCAL_REGION)
+ .setRegistryEndpoint(url.getHost())
+ .setRegistryEndpointPort(url.getPort()).build();
+
+ DefaultRegistryClient registryClient = new
DefaultRegistryClient(config);
+ registryClient.init();
+ return registryClient;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public void doRegister(URL url) {
+ if (!url.getParameter(Constants.REGISTER_KEY, true)
+ || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol())) {
+ return;
+ }
+
+ String serviceName = buildServiceName(url);
+ String serviceData = url.toFullString();
+
+ PublisherRegistration registration = new
PublisherRegistration(serviceName);
+ addAttributesForPub(registration);
+
+ registryClient.register(registration, serviceData);
+ }
+
+ /**
+ * Add attributes for pub.
+ *
+ * @param publisherRegistration the publisher registration
+ */
+ protected void addAttributesForPub(PublisherRegistration
publisherRegistration) {
+ publisherRegistration.setGroup(DEFAULT_GROUP);
+ }
+
+ @Override
+ public void doUnregister(URL url) {
+ if (!url.getParameter(Constants.REGISTER_KEY, true)
+ || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol())) {
+ return;
+ }
+ String serviceName = buildServiceName(url);
+ registryClient.unregister(serviceName, DEFAULT_GROUP,
RegistryType.PUBLISHER);
+ }
+
+ @Override
+ public void doSubscribe(URL url, final NotifyListener listener) {
+ if (!url.getParameter(Constants.SUBSCRIBE_KEY, true)
+ || Constants.PROVIDER_PROTOCOL.equals(url.getProtocol())) {
+ return;
+ }
+
+ String serviceName = buildServiceName(url);
+ // com.alipay.test.TestService:1.0:group@dubbo
+ Subscriber listSubscriber = subscribers.get(serviceName);
+
+ if (listSubscriber != null) {
+ LOGGER.warn("Service name [" + serviceName + "] have bean
registered in SOFARegistry.");
+
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ handleRegistryData(listSubscriber.peekData(), listener,
countDownLatch);
+ waitAddress(serviceName, countDownLatch);
+ return;
+ }
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ SubscriberRegistration subscriberRegistration = new
SubscriberRegistration(serviceName,
+ (dataId, data) -> {
+ //record change
+ printAddressData(dataId, data);
+ handleRegistryData(data, listener, latch);
+ });
+
+ addAttributesForSub(subscriberRegistration);
+ listSubscriber = registryClient.register(subscriberRegistration);
+
+ subscribers.put(serviceName, listSubscriber);
+
+ waitAddress(serviceName, latch);
+ }
+
+ private void waitAddress(String serviceName, CountDownLatch
countDownLatch) {
+ try {
+ if (!countDownLatch.await(waitAddressTimeout,
TimeUnit.MILLISECONDS)) {
+ LOGGER.warn("Subscribe data failed by dataId " + serviceName);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error when wait Address!", e);
+ }
+ }
+
+ @Override
+ public void doUnsubscribe(URL url, NotifyListener listener) {
+ if (!url.getParameter(Constants.SUBSCRIBE_KEY, true)
+ || Constants.PROVIDER_PROTOCOL.equals(url.getProtocol())) {
+ return;
+ }
+ String serviceName = buildServiceName(url);
+
+ registryClient.unregister(serviceName, DEFAULT_GROUP,
RegistryType.SUBSCRIBER);
+ }
+
+ private void handleRegistryData(UserData data, NotifyListener
notifyListener,
+ CountDownLatch latch) {
+ try {
+ List<URL> urls = new ArrayList<>();
+ if (null != data) {
+
+ List<String> datas = flatUserData(data);
+ for (String serviceUrl : datas) {
+ URL url = URL.valueOf(serviceUrl);
+ String serverApplication =
url.getParameter(Constants.APPLICATION_KEY);
+ if (StringUtils.isNotEmpty(serverApplication)) {
+ url = url.addParameter("dstApp", serverApplication);
+ }
+ urls.add(url);
+ }
+ }
+ notifyListener.notify(urls);
+ } finally {
+ latch.countDown();
+ }
+ }
+
+ private String buildServiceName(URL url) {
+ // return url.getServiceKey();
+ StringBuilder buf = new StringBuilder();
+ buf.append(url.getServiceInterface());
+ String version = url.getParameter(Constants.VERSION_KEY);
+ if (StringUtils.isNotEmpty(version)) {
+ buf.append(":").append(version);
+ }
+ String group = url.getParameter(Constants.GROUP_KEY);
+ if (StringUtils.isNotEmpty(group)) {
+ buf.append(":").append(group);
+ }
+ buf.append("@").append(Constants.DUBBO);
+ return buf.toString();
+ }
+
+ /**
+ * Print address data.
+ *
+ * @param dataId the data id
+ * @param userData the user data
+ */
+ protected void printAddressData(String dataId, UserData userData) {
+
+ List<String> datas;
+ if (userData == null) {
+ datas = new ArrayList<>(0);
+ } else {
+ datas = flatUserData(userData);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (String provider : datas) {
+ sb.append(" >>> ").append(provider).append("\n");
+ }
+ if (LOGGER.isInfoEnabled()) {
+ LOGGER.info("Receive updated RPC service addresses: service[" +
dataId
+ + "]\n .Available target addresses size [" + datas.size()
+ "]\n"
+ + sb.toString());
+ }
+ }
+
+ /**
+ * Add attributes for sub.
+ *
+ * @param subscriberRegistration the subscriber registration
+ */
+ protected void addAttributesForSub(SubscriberRegistration
subscriberRegistration) {
+ subscriberRegistration.setGroup(DEFAULT_GROUP);
+ subscriberRegistration.setScopeEnum(ScopeEnum.global);
+ }
+
+ /**
+ * Flat user data list.
+ *
+ * @param userData the user data
+ * @return the list
+ */
+ protected List<String> flatUserData(UserData userData) {
+ List<String> result = new ArrayList<>();
+ Map<String, List<String>> zoneData = userData.getZoneData();
+
+ for (Map.Entry<String, List<String>> entry : zoneData.entrySet()) {
+ result.addAll(entry.getValue());
+ }
+
+ return result;
+ }
+}
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
new file mode 100644
index 0000000..f832e80
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
@@ -0,0 +1,43 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+/**
+ * @since 2.7.2
+ */
+public class SofaRegistryConstants {
+
+ /**
+ * Default data center
+ */
+ public static final String LOCAL_DATA_CENTER = "DefaultDataCenter";
+
+ /**
+ * Default region
+ */
+ public static final String LOCAL_REGION = "DEFAULT_ZONE";
+
+ /**
+ * Default group
+ */
+ public static final String DEFAULT_GROUP = "SOFA";
+
+ /**
+ * parameter for address.wait.time of rpc reference
+ */
+ public static final String ADDRESS_WAIT_TIME_KEY =
"rpc.reference.address.wait.time";
+}
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
new file mode 100644
index 0000000..18a7809
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.support.AbstractRegistryFactory;
+
+/**
+ * @since 2.7.2
+ */
+public class SofaRegistryFactory extends AbstractRegistryFactory {
+
+ @Override
+ protected Registry createRegistry(URL url) {
+ initEnvironment(url);
+ return new SofaRegistry(url);
+ }
+
+ /**
+ * For extension, such as load zone/accessKey/secretKey/...
+ *
+ * @param url URL
+ */
+ protected void initEnvironment(URL url) {
+ }
+}
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
new file mode 100644
index 0000000..dff4cbb
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
@@ -0,0 +1 @@
+sofa=org.apache.dubbo.registry.sofa.SofaRegistryFactory
\ No newline at end of file
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.java
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.java
new file mode 100644
index 0000000..cc66a5e
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.java
@@ -0,0 +1,24 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+/**
+ */
+public interface HelloService {
+
+ String sayHello(String name);
+}
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
new file mode 100644
index 0000000..a9fb0ca
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.server.test.TestRegistryMain;
+
+/**
+ */
+public class HelloServiceImpl implements HelloService {
+
+ private final String result;
+
+ public HelloServiceImpl(String result) {
+ this.result = result;
+ }
+
+ @Override
+ public String sayHello(String name) {
+ return result != null ? result : "hello, " + name + "!";
+ }
+
+ public static void main(String[] args) {
+ TestRegistryMain registryMain = new TestRegistryMain();
+ try {
+ registryMain.startRegistry();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
new file mode 100644
index 0000000..4d67b74
--- /dev/null
+++
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.server.test.TestRegistryMain;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ */
+public class SofaRegistryTest {
+
+ public static final Logger LOGGER =
LoggerFactory.getLogger(SofaRegistryTest.class);
+
+ private static TestRegistryMain registryMain;
+
+ private static ApplicationConfig applicationConfig = new
ApplicationConfig("test-sofa-registry");
+
+ private static ProtocolConfig protocolConfig1;
+
+ private static ProtocolConfig protocolConfig2;
+
+ private static RegistryConfig registryConfig;
+
+ @BeforeAll
+ public static void beforeClass() {
+
+ protocolConfig1 = new ProtocolConfig();
+ protocolConfig1.setName("dubbo");
+ protocolConfig1.setPort(20890);
+
+ protocolConfig2 = new ProtocolConfig();
+ protocolConfig2.setName("dubbo");
+ protocolConfig2.setPort(20891);
+
+ registryConfig = new RegistryConfig();
+ registryConfig.setAddress("sofa://127.0.0.1:9603");
+ registryConfig.setProtocol("sofa");
+
+ registryMain = new TestRegistryMain();
+ try {
+ registryMain.startRegistry();
+ } catch (Exception e) {
+ LOGGER.error("start test sofa registry error!", e);
+ }
+ }
+
+ @Test
+ public void testPubAndSub() throws InterruptedException {
+
+ ServiceConfig<HelloService> serviceConfig1 = new ServiceConfig<>();
+ serviceConfig1.setInterface(HelloService.class);
+ serviceConfig1.setRef(new HelloServiceImpl("rrr11"));
+ serviceConfig1.setProtocol(protocolConfig1);
+ serviceConfig1.setRegistry(registryConfig);
+ serviceConfig1.setGroup("g1");
+ serviceConfig1.setApplication(applicationConfig);
+ serviceConfig1.export();
+
+ ServiceConfig<HelloService> serviceConfig2 = new ServiceConfig<>();
+ serviceConfig2.setInterface(HelloService.class);
+ serviceConfig2.setRef(new HelloServiceImpl("rrr22"));
+ serviceConfig2.setProtocol(protocolConfig1);
+ serviceConfig2.setRegistry(registryConfig);
+ serviceConfig2.setGroup("g2");
+ serviceConfig2.setApplication(applicationConfig);
+ serviceConfig2.setRegister(false);
+ serviceConfig2.export();
+
+ Thread.sleep(1000);
+
+ // do refer
+ ReferenceConfig<HelloService> referenceConfig1 = new
ReferenceConfig<>();
+ referenceConfig1.setInterface(HelloService.class);
+ referenceConfig1.setProtocol("dubbo");
+ referenceConfig1.setInjvm(false);
+ referenceConfig1.setGroup("g1");
+ referenceConfig1.setRegistry(registryConfig);
+ referenceConfig1.setApplication(applicationConfig);
+ HelloService service = referenceConfig1.get();
+ Assertions.assertEquals("rrr11", service.sayHello("xxx"));
+
+ // do refer duplicated
+ ReferenceConfig<HelloService> referenceConfig2 = new
ReferenceConfig<>();
+ referenceConfig2.setInterface(HelloService.class);
+ referenceConfig2.setProtocol("dubbo");
+ referenceConfig2.setInjvm(false);
+ referenceConfig2.setGroup("g1");
+ referenceConfig2.setRegistry(registryConfig);
+ referenceConfig2.setApplication(applicationConfig);
+ HelloService service2 = referenceConfig2.get();
+ Assertions.assertEquals("rrr11", service2.sayHello("xxx"));
+
+ // export one service
+ ServiceConfig<HelloService> serviceConfig3 = new ServiceConfig<>();
+ serviceConfig3.setInterface(HelloService.class);
+ serviceConfig3.setRef(new HelloServiceImpl("rrr12"));
+ serviceConfig3.setProtocol(protocolConfig2);
+ serviceConfig3.setRegistry(registryConfig);
+ serviceConfig3.setGroup("g1");
+ serviceConfig3.setApplication(applicationConfig);
+ serviceConfig3.export();
+ Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+
+ // unrefer
+ referenceConfig1.destroy();
+ Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+
+ // unexport one service
+ serviceConfig1.unexport();
+ Thread.sleep(2000);
+ Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+ }
+
+ @AfterAll
+ public static void afterClass() {
+ try {
+ registryMain.stopRegistry();
+ protocolConfig1.destroy();
+ } catch (Exception e) {
+ LOGGER.error("Stop test sofa registry error!", e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git
a/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties
b/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties
new file mode 100644
index 0000000..15a0900
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties
@@ -0,0 +1,7 @@
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}]
%t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml
index c9c3441..962148b 100644
--- a/dubbo-registry/pom.xml
+++ b/dubbo-registry/pom.xml
@@ -37,5 +37,6 @@
<module>dubbo-registry-consul</module>
<module>dubbo-registry-etcd3</module>
<module>dubbo-registry-nacos</module>
+ <module>dubbo-registry-sofa</module>
</modules>
</project>
diff --git
a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
index ceef6cc..564505a 100644
---
a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
+++
b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.protocol.thrift;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.Codec2;
import org.apache.dubbo.remoting.buffer.ChannelBuffer;
@@ -29,8 +30,6 @@ import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.RpcResult;
import
org.apache.dubbo.rpc.protocol.thrift.io.RandomAccessByteArrayOutputStream;
-
-import org.apache.commons.lang.StringUtils;
import org.apache.thrift.TApplicationException;
import org.apache.thrift.TBase;
import org.apache.thrift.TException;