diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index 6dc00fbcda76..5164d860cd29 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -485,6 +485,13 @@
compile
true
+
+ org.apache.dubbo
+ dubbo-metadata-report-nacos
+ ${project.version}
+ compile
+ true
+
@@ -613,6 +620,7 @@
org.apache.dubbo:dubbo-metadata-report-zookeeper
org.apache.dubbo:dubbo-metadata-report-consul
org.apache.dubbo:dubbo-metadata-report-etcd
+ org.apache.dubbo:dubbo-metadata-report-nacos
org.apache.dubbo:dubbo-serialization-native-hession
org.apache.dubbo:dubbo-rpc-native-thrift
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index 2b1e5feb2f62..e6f6eb8c011e 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -382,6 +382,11 @@
dubbo-metadata-report-etcd
${project.version}
+
+ org.apache.dubbo
+ dubbo-metadata-report-nacos
+ ${project.version}
+
org.apache.dubbo
dubbo-configcenter-api
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml b/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml
new file mode 100644
index 000000000000..d324d5c49c18
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+ dubbo-metadata-report
+ org.apache.dubbo
+ ${revision}
+
+ 4.0.0
+
+ dubbo-metadata-report-nacos
+
+
+
+ org.apache.dubbo
+ dubbo-metadata-report-api
+ ${project.parent.version}
+
+
+ com.alibaba.nacos
+ nacos-client
+
+
+
+
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
new file mode 100644
index 000000000000..03bdeb8f9585
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
@@ -0,0 +1,125 @@
+/*
+ * 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.metadata.store.nacos;
+
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.exception.NacosException;
+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.StringUtils;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
+import org.apache.dubbo.metadata.support.AbstractMetadataReport;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.Properties;
+
+import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
+import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
+import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
+import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
+import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
+import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
+
+/**
+ * metadata report impl for nacos
+ */
+public class NacosMetadataReport extends AbstractMetadataReport {
+ private static final Logger logger = LoggerFactory.getLogger(NacosMetadataReport.class);
+ private ConfigService configService;
+
+ public NacosMetadataReport(URL url) {
+ super(url);
+ this.configService = buildConfigService(url);
+ }
+
+ public ConfigService buildConfigService(URL url) {
+ Properties nacosProperties = buildNacosProperties(url);
+ try {
+ configService = NacosFactory.createConfigService(nacosProperties);
+ } catch (NacosException e) {
+ if (logger.isErrorEnabled()) {
+ logger.error(e.getErrMsg(), e);
+ }
+ throw new IllegalStateException(e);
+ }
+ return configService;
+ }
+
+ private Properties buildNacosProperties(URL url) {
+ Properties properties = new Properties();
+ setServerAddr(url, properties);
+ setProperties(url, properties);
+ return properties;
+ }
+
+ private void setServerAddr(URL url, Properties properties) {
+ StringBuilder serverAddrBuilder =
+ new StringBuilder(url.getHost()) // Host
+ .append(":")
+ .append(url.getPort()); // Port
+ // Append backup parameter as other servers
+ String backup = url.getParameter(BACKUP_KEY);
+ if (backup != null) {
+ serverAddrBuilder.append(",").append(backup);
+ }
+ String serverAddr = serverAddrBuilder.toString();
+ properties.put(SERVER_ADDR, serverAddr);
+ }
+
+ private void setProperties(URL url, Properties properties) {
+ putPropertyIfAbsent(url, properties, NAMESPACE);
+ putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
+ putPropertyIfAbsent(url, properties, ENDPOINT);
+ putPropertyIfAbsent(url, properties, ACCESS_KEY);
+ putPropertyIfAbsent(url, properties, SECRET_KEY);
+ putPropertyIfAbsent(url, properties, CLUSTER_NAME);
+ }
+
+ private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {
+ String propertyValue = url.getParameter(propertyName);
+ if (StringUtils.isNotEmpty(propertyValue)) {
+ properties.setProperty(propertyName, propertyValue);
+ }
+ }
+
+ @Override
+ protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {
+ this.storeMetadata(providerMetadataIdentifier, serviceDefinitions);
+ }
+
+ @Override
+ protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {
+ this.storeMetadata(consumerMetadataIdentifier, value);
+ }
+
+ private void storeMetadata(MetadataIdentifier identifier, String value) {
+ try {
+ boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), identifier.getGroup(), value);
+ if (!publishResult) {
+ throw new RuntimeException("publish nacos metadata failed");
+ }
+ } catch (Throwable t) {
+ logger.error("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t);
+ throw new RpcException("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t);
+ }
+ }
+}
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java
new file mode 100644
index 000000000000..b882042281c5
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.metadata.store.nacos;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.metadata.store.MetadataReport;
+import org.apache.dubbo.metadata.support.AbstractMetadataReportFactory;
+
+/**
+ * metadata report factory impl for nacos
+ */
+public class NacosMetadataReportFactory extends AbstractMetadataReportFactory {
+ @Override
+ protected MetadataReport createMetadataReport(URL url) {
+ return new NacosMetadataReport(url);
+ }
+}
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
new file mode 100644
index 000000000000..de3b50a4b415
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
@@ -0,0 +1 @@
+nacos=org.apache.dubbo.metadata.store.nacos.NacosMetadataReportFactory
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java
new file mode 100644
index 000000000000..e84efc529caa
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.metadata.store.nacos;
+
+/**
+ * Test interface for Nacos metadata report
+ */
+public interface NacosMetadata4TstService {
+
+ int getCounter();
+
+ void printResult(String var);
+}
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java
new file mode 100644
index 000000000000..c90809c3d51c
--- /dev/null
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.metadata.store.nacos;
+
+import com.alibaba.nacos.api.config.ConfigService;
+import com.google.gson.Gson;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;
+import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Disabled;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.RegistryConstants.SESSION_TIMEOUT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
+import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
+
+@Disabled
+public class NacosMetadataReportTest {
+ private static final String TEST_SERVICE = "org.apache.dubbo.metadata.store.nacos.NacosMetadata4TstService";
+ private NacosMetadataReport nacosMetadataReport;
+ private NacosMetadataReportFactory nacosMetadataReportFactory;
+ private ConfigService configService;
+
+ @BeforeEach
+ public void setUp() {
+ // timeout in 15 seconds.
+ URL url = URL.valueOf("nacos://127.0.0.1:8848")
+ .addParameter(SESSION_TIMEOUT_KEY, 15000);
+ nacosMetadataReportFactory = new NacosMetadataReportFactory();
+ this.nacosMetadataReport = (NacosMetadataReport) nacosMetadataReportFactory.createMetadataReport(url);
+ this.configService = nacosMetadataReport.buildConfigService(url);
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testStoreProvider() throws Exception {
+ String version = "1.0.0";
+ String group = null;
+ String application = "nacos-metdata-report-test";
+ MetadataIdentifier providerIdentifier =
+ storeProvider(nacosMetadataReport, TEST_SERVICE, version, group, application);
+ String serverContent = configService.getConfig(providerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, 5000L);
+ Assertions.assertNotNull(serverContent);
+
+ Gson gson = new Gson();
+ FullServiceDefinition fullServiceDefinition = gson.fromJson(serverContent, FullServiceDefinition.class);
+ Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "nacosTest");
+ }
+
+ @Test
+ public void testStoreConsumer() throws Exception {
+ String version = "1.0.0";
+ String group = null;
+ String application = "nacos-metadata-report-consumer-test";
+ MetadataIdentifier consumerIdentifier = storeConsumer(nacosMetadataReport, TEST_SERVICE, version, group, application);
+
+ String serverContent = configService.getConfig(consumerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, 5000L);
+ Assertions.assertNotNull(serverContent);
+ Assertions.assertEquals(serverContent, "{\"paramConsumerTest\":\"nacosConsumer\"}");
+ }
+
+ private MetadataIdentifier storeProvider(NacosMetadataReport nacosMetadataReport, String interfaceName, String version,
+ String group, String application)
+ throws ClassNotFoundException, InterruptedException {
+ URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName +
+ "?paramTest=nacosTest&version=" + version + "&application="
+ + application + (group == null ? "" : "&group=" + group));
+
+ MetadataIdentifier providerMetadataIdentifier =
+ new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application);
+ Class interfaceClass = Class.forName(interfaceName);
+ FullServiceDefinition fullServiceDefinition =
+ ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, url.getParameters());
+
+ nacosMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition);
+ Thread.sleep(1000);
+ return providerMetadataIdentifier;
+ }
+
+ private MetadataIdentifier storeConsumer(NacosMetadataReport nacosMetadataReport, String interfaceName,
+ String version, String group, String application) throws InterruptedException {
+ MetadataIdentifier consumerIdentifier = new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application);
+ Map tmp = new HashMap<>();
+ tmp.put("paramConsumerTest", "nacosConsumer");
+ nacosMetadataReport.storeConsumerMetadata(consumerIdentifier, tmp);
+ Thread.sleep(1000);
+ return consumerIdentifier;
+ }
+}
diff --git a/dubbo-metadata-report/pom.xml b/dubbo-metadata-report/pom.xml
index 3cb254afb961..5e0fb1a42877 100644
--- a/dubbo-metadata-report/pom.xml
+++ b/dubbo-metadata-report/pom.xml
@@ -31,6 +31,7 @@
dubbo-metadata-definition
dubbo-metadata-report-consul
dubbo-metadata-report-etcd
+ dubbo-metadata-report-nacos