Skip to content

Commit f95e29a

Browse files
moriadryralf0131
authored andcommitted
[Dubbo-3846] Support Nacos as config center (#3988)
1 parent 5fd41d7 commit f95e29a

File tree

10 files changed

+510
-1
lines changed

10 files changed

+510
-1
lines changed

dubbo-all/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,13 @@
415415
<scope>compile</scope>
416416
<optional>true</optional>
417417
</dependency>
418+
<dependency>
419+
<groupId>org.apache.dubbo</groupId>
420+
<artifactId>dubbo-configcenter-nacos</artifactId>
421+
<version>${project.version}</version>
422+
<scope>compile</scope>
423+
<optional>true</optional>
424+
</dependency>
418425
<dependency>
419426
<groupId>org.apache.dubbo</groupId>
420427
<artifactId>dubbo-configcenter-consul</artifactId>
@@ -599,6 +606,7 @@
599606
<include>org.apache.dubbo:dubbo-configcenter-zookeeper</include>
600607
<include>org.apache.dubbo:dubbo-configcenter-consul</include>
601608
<include>org.apache.dubbo:dubbo-configcenter-etcd</include>
609+
<include>org.apache.dubbo:dubbo-configcenter-nacos</include>
602610
<include>org.apache.dubbo:dubbo-metadata-report-api</include>
603611
<include>org.apache.dubbo:dubbo-metadata-definition</include>
604612
<include>org.apache.dubbo:dubbo-metadata-report-redis</include>

dubbo-bom/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@
257257
<artifactId>dubbo-registry-consul</artifactId>
258258
<version>${project.version}</version>
259259
</dependency>
260+
<dependency>
261+
<groupId>org.apache.dubbo</groupId>
262+
<artifactId>dubbo-registry-nacos</artifactId>
263+
<version>${project.version}</version>
264+
</dependency>
260265
<dependency>
261266
<groupId>org.apache.dubbo</groupId>
262267
<artifactId>dubbo-registry-sofa</artifactId>
@@ -402,6 +407,11 @@
402407
<artifactId>dubbo-configcenter-etcd</artifactId>
403408
<version>${project.version}</version>
404409
</dependency>
410+
<dependency>
411+
<groupId>org.apache.dubbo</groupId>
412+
<artifactId>dubbo-configcenter-nacos</artifactId>
413+
<version>${project.version}</version>
414+
</dependency>
405415
<dependency>
406416
<groupId>org.apache.dubbo</groupId>
407417
<artifactId>dubbo-metadata-definition</artifactId>

dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ public class Constants {
200200

201201
public static final String PROPERTIES_CHAR_SEPERATOR = "-";
202202

203+
public static final String GROUP_CHAR_SEPERATOR = ":";
204+
203205
public static final String HIDE_KEY_PREFIX = ".";
204206

205207
public static final String DEFAULT_KEY_PREFIX = "default.";
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to You under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
19+
<project xmlns="http://maven.apache.org/POM/4.0.0"
20+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
21+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
22+
<parent>
23+
<artifactId>dubbo-configcenter</artifactId>
24+
<groupId>org.apache.dubbo</groupId>
25+
<version>${revision}</version>
26+
</parent>
27+
<modelVersion>4.0.0</modelVersion>
28+
29+
<artifactId>dubbo-configcenter-nacos</artifactId>
30+
<packaging>jar</packaging>
31+
<name>${project.artifactId}</name>
32+
<description>The nacos implementation of the config-center api</description>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>org.apache.dubbo</groupId>
37+
<artifactId>dubbo-configcenter-api</artifactId>
38+
<version>${project.parent.version}</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.alibaba.nacos</groupId>
42+
<artifactId>nacos-client</artifactId>
43+
</dependency>
44+
</dependencies>
45+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.dubbo.configcenter.support.nacos;
19+
20+
import com.alibaba.nacos.api.NacosFactory;
21+
import com.alibaba.nacos.api.config.ConfigService;
22+
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
23+
import com.alibaba.nacos.api.exception.NacosException;
24+
import org.apache.dubbo.common.URL;
25+
import org.apache.dubbo.common.logger.Logger;
26+
import org.apache.dubbo.common.logger.LoggerFactory;
27+
import org.apache.dubbo.common.utils.StringUtils;
28+
import org.apache.dubbo.configcenter.ConfigChangeEvent;
29+
import org.apache.dubbo.configcenter.ConfigChangeType;
30+
import org.apache.dubbo.configcenter.ConfigurationListener;
31+
import org.apache.dubbo.configcenter.DynamicConfiguration;
32+
33+
import java.util.Map;
34+
import java.util.Properties;
35+
import java.util.Set;
36+
import java.util.concurrent.Executor;
37+
import java.util.concurrent.ConcurrentMap;
38+
import java.util.concurrent.ConcurrentHashMap;
39+
import java.util.concurrent.CopyOnWriteArraySet;
40+
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
41+
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
42+
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
43+
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
44+
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
45+
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
46+
import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
47+
import static org.apache.dubbo.common.Constants.BACKUP_KEY;
48+
import static org.apache.dubbo.common.Constants.CONFIG_NAMESPACE_KEY;
49+
import static org.apache.dubbo.common.Constants.GROUP_CHAR_SEPERATOR;
50+
import static org.apache.dubbo.common.Constants.PROPERTIES_CHAR_SEPERATOR;
51+
52+
/**
53+
* The nacos implementation of {@link DynamicConfiguration}
54+
*/
55+
public class NacosDynamicConfiguration implements DynamicConfiguration {
56+
57+
private final Logger logger = LoggerFactory.getLogger(getClass());
58+
59+
/**
60+
* The final root path would be: /$NAME_SPACE/config
61+
*/
62+
private String rootPath;
63+
64+
/**
65+
* The nacos configService
66+
*/
67+
68+
private ConfigService configService;
69+
70+
/**
71+
* The map store the key to {@link NacosConfigListener} mapping
72+
*/
73+
private final ConcurrentMap<String, NacosConfigListener> watchListenerMap;
74+
75+
NacosDynamicConfiguration(URL url) {
76+
rootPath = url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + "-config";
77+
buildConfigService(url);
78+
watchListenerMap = new ConcurrentHashMap<>();
79+
}
80+
81+
private ConfigService buildConfigService(URL url) {
82+
Properties nacosProperties = buildNacosProperties(url);
83+
try {
84+
configService = NacosFactory.createConfigService(nacosProperties);
85+
} catch (NacosException e) {
86+
if (logger.isErrorEnabled()) {
87+
logger.error(e.getErrMsg(), e);
88+
}
89+
throw new IllegalStateException(e);
90+
}
91+
return configService;
92+
}
93+
94+
public void publishNacosConfig(String key, String value) {
95+
try {
96+
String[] keyAndGroup = getKeyAndGroup(key);
97+
configService.publishConfig(keyAndGroup[0], keyAndGroup[1], value);
98+
} catch (NacosException e) {
99+
logger.error(e.getErrMsg());
100+
}
101+
}
102+
103+
private String[] getKeyAndGroup(String key) {
104+
int i = key.lastIndexOf(GROUP_CHAR_SEPERATOR);
105+
if (i < 0) {
106+
return new String[]{key, null};
107+
} else {
108+
return new String[]{key.substring(0, i), key.substring(i+1)};
109+
}
110+
}
111+
112+
private Properties buildNacosProperties(URL url) {
113+
Properties properties = new Properties();
114+
setServerAddr(url, properties);
115+
setProperties(url, properties);
116+
return properties;
117+
}
118+
119+
private void setServerAddr(URL url, Properties properties) {
120+
StringBuilder serverAddrBuilder =
121+
new StringBuilder(url.getHost()) // Host
122+
.append(":")
123+
.append(url.getPort()); // Port
124+
125+
// Append backup parameter as other servers
126+
String backup = url.getParameter(BACKUP_KEY);
127+
if (backup != null) {
128+
serverAddrBuilder.append(",").append(backup);
129+
}
130+
String serverAddr = serverAddrBuilder.toString();
131+
properties.put(SERVER_ADDR, serverAddr);
132+
}
133+
134+
private void setProperties(URL url, Properties properties) {
135+
putPropertyIfAbsent(url, properties, NAMESPACE);
136+
putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
137+
putPropertyIfAbsent(url, properties, ENDPOINT);
138+
putPropertyIfAbsent(url, properties, ACCESS_KEY);
139+
putPropertyIfAbsent(url, properties, SECRET_KEY);
140+
putPropertyIfAbsent(url, properties, CLUSTER_NAME);
141+
}
142+
143+
private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {
144+
String propertyValue = url.getParameter(propertyName);
145+
if (StringUtils.isNotEmpty(propertyValue)) {
146+
properties.setProperty(propertyName, propertyValue);
147+
}
148+
}
149+
150+
/**
151+
* Ignores the group parameter.
152+
*
153+
* @param key property key the native listener will listen on
154+
* @param group to distinguish different set of properties
155+
* @return
156+
*/
157+
private NacosConfigListener createTargetListener(String key, String group) {
158+
NacosConfigListener configListener = new NacosConfigListener();
159+
configListener.fillContext(key, group);
160+
return configListener;
161+
}
162+
163+
@Override
164+
public void addListener(String key, String group, ConfigurationListener listener) {
165+
String[] keyAndGroup = getKeyAndGroup(key);
166+
if (keyAndGroup[1] != null) {
167+
group = keyAndGroup[1];
168+
}
169+
String finalGroup = group;
170+
NacosConfigListener nacosConfigListener = watchListenerMap.computeIfAbsent(generateKey(key, group), k -> createTargetListener(key, finalGroup));
171+
String keyInNacos = rootPath + PROPERTIES_CHAR_SEPERATOR + key;
172+
nacosConfigListener.addListener(listener);
173+
try {
174+
configService.addListener(keyInNacos, group, nacosConfigListener);
175+
System.out.println("1");
176+
} catch (NacosException e) {
177+
logger.error(e.getMessage());
178+
}
179+
}
180+
181+
private String generateKey(String key, String group) {
182+
if (StringUtils.isNotEmpty(group)) {
183+
key = key + GROUP_CHAR_SEPERATOR + group;
184+
}
185+
return key;
186+
}
187+
188+
@Override
189+
public void removeListener(String key, String group, ConfigurationListener listener) {
190+
NacosConfigListener eventListener = watchListenerMap.get(generateKey(key, group));
191+
if (eventListener != null) {
192+
eventListener.removeListener(listener);
193+
}
194+
}
195+
196+
@Override
197+
public String getConfig(String key, String group, long timeout) throws IllegalStateException {
198+
key = generateKey(key, group);
199+
return (String) getInternalProperty(rootPath + PROPERTIES_CHAR_SEPERATOR + key);
200+
}
201+
202+
@Override
203+
public Object getInternalProperty(String key) {
204+
try {
205+
String[] keyAndGroup = getKeyAndGroup(key);
206+
return configService.getConfig(keyAndGroup[0], keyAndGroup[1], 5000L);
207+
} catch (NacosException e) {
208+
logger.error(e.getMessage());
209+
}
210+
return null;
211+
}
212+
213+
public class NacosConfigListener extends AbstractSharedListener {
214+
215+
private Set<ConfigurationListener> listeners = new CopyOnWriteArraySet<>();
216+
/**
217+
* cache data to store old value
218+
*/
219+
private Map<String, String> cacheData = new ConcurrentHashMap<>();
220+
221+
@Override
222+
public Executor getExecutor() {
223+
return null;
224+
}
225+
226+
/**
227+
* receive
228+
*
229+
* @param dataId data ID
230+
* @param group group
231+
* @param configInfo content
232+
*/
233+
@Override
234+
public void innerReceive(String dataId, String group, String configInfo) {
235+
String oldValue = cacheData.get(dataId);
236+
ConfigChangeEvent event = new ConfigChangeEvent(dataId, configInfo, getChangeType(configInfo, oldValue));
237+
if (configInfo == null) {
238+
cacheData.remove(dataId);
239+
} else {
240+
cacheData.put(dataId, configInfo);
241+
}
242+
listeners.forEach(listener -> listener.process(event));
243+
}
244+
245+
void addListener(ConfigurationListener configurationListener) {
246+
247+
this.listeners.add(configurationListener);
248+
}
249+
250+
void removeListener(ConfigurationListener configurationListener) {
251+
this.listeners.remove(configurationListener);
252+
}
253+
254+
private ConfigChangeType getChangeType(String configInfo, String oldValue) {
255+
if (StringUtils.isBlank(configInfo)) {
256+
return ConfigChangeType.DELETED;
257+
}
258+
if (StringUtils.isBlank(oldValue)) {
259+
return ConfigChangeType.ADDED;
260+
}
261+
return ConfigChangeType.MODIFIED;
262+
}
263+
}
264+
265+
}

0 commit comments

Comments
 (0)