Skip to content

Commit 3a24ea0

Browse files
authored
support proxy druid (#3993)
1 parent 113273b commit 3a24ea0

File tree

5 files changed

+193
-14
lines changed

5 files changed

+193
-14
lines changed

spring-cloud-alibaba-starters/spring-alibaba-nacos-config/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@
3737
<artifactId>spring-boot-starter-web</artifactId>
3838
<scope>test</scope>
3939
</dependency>
40-
40+
<dependency>
41+
<groupId>com.alibaba</groupId>
42+
<artifactId>druid</artifactId>
43+
<version>1.2.25</version>
44+
<scope>provided</scope>
45+
</dependency>
4146
<dependency>
4247
<groupId>org.springframework</groupId>
4348
<artifactId>spring-web</artifactId>

spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosAnnotationProcessor.java

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,19 @@ public int getOrder() {
7373
private Map<String, TargetRefreshable> targetListenerMap = new ConcurrentHashMap<>();
7474
private Map<String, AtomicReference<String>> groupKeyCache = new ConcurrentHashMap<>();
7575

76-
private String getGroupKeyContent(String dataId, String group) throws Exception {
76+
private String getGroupKeyContent(String dataId, String group, boolean refreshed) throws Exception {
7777
if (groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
7878
return groupKeyCache.get(GroupKey.getKey(dataId, group)).get();
7979
}
8080
synchronized (this) {
8181
if (!groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
8282
String content = getNacosConfigManager().getConfigService().getConfig(dataId, group, 5000);
8383
groupKeyCache.put(GroupKey.getKey(dataId, group), new AtomicReference<>(content));
84-
84+
if (!refreshed) {
85+
log.info("[Nacos Config] refreshed is set to false, not listening config for annotation: dataId={}, group={}", dataId,
86+
group);
87+
return content;
88+
}
8589
log.info("[Nacos Config] Listening config for annotation: dataId={}, group={}", dataId,
8690
group);
8791
getNacosConfigManager().getConfigService().addListener(dataId, group, new AbstractListener() {
@@ -115,7 +119,7 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw
115119
Class clazz = bean.getClass();
116120
NacosConfig annotationBean = AnnotationUtils.findAnnotation(clazz, NacosConfig.class);
117121
if (annotationBean != null) {
118-
handleBeanNacosConfigAnnotation(annotationBean.dataId(), annotationBean.group(), annotationBean.key(), beanName, bean, annotationBean.defaultValue());
122+
handleBeanNacosConfigAnnotation(annotationBean.dataId(), annotationBean.group(), annotationBean.key(), annotationBean.refreshed(), beanName, bean, annotationBean.defaultValue());
119123
return bean;
120124
}
121125

@@ -147,10 +151,10 @@ private void handleFiledAnnotation(Object bean, String beanName, Field field) {
147151
}
148152
}
149153

150-
private void handleBeanNacosConfigAnnotation(String dataId, String group, String key, String beanName, Object bean,
154+
private void handleBeanNacosConfigAnnotation(String dataId, String group, String key, boolean refreshed, String beanName, Object bean,
151155
String defaultValue) {
152156
try {
153-
String config = getDestContent(getGroupKeyContent(dataId, group), key);
157+
String config = getDestContent(getGroupKeyContent(dataId, group, refreshed), key);
154158
if (!org.springframework.util.StringUtils.hasText(config)) {
155159
config = defaultValue;
156160
}
@@ -163,6 +167,10 @@ private void handleBeanNacosConfigAnnotation(String dataId, String group, String
163167
}
164168

165169
String refreshTargetKey = beanName + "#instance#";
170+
if (!refreshed) {
171+
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
172+
return;
173+
}
166174
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
167175
if (currentTarget != null) {
168176
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
@@ -270,7 +278,7 @@ public String toString() {
270278
return String.format("sca nacos config listener on bean method %s", bean + "#" + methodSignature(method));
271279
}
272280
};
273-
nacosPropertiesKeyListener.setLastContent(getGroupKeyContent(dataId, group));
281+
nacosPropertiesKeyListener.setLastContent(getGroupKeyContent(dataId, group, true));
274282
getNacosConfigManager().getConfigService().addListener(dataId, group,
275283
nacosPropertiesKeyListener);
276284
targetListenerMap.put(refreshTargetKey, nacosPropertiesKeyListener);
@@ -309,7 +317,7 @@ private void handleMethodNacosConfigListener(NacosConfigListener annotation, Str
309317
"@NacosConfigListener must be over a method with a single parameter");
310318
}
311319

312-
String configInfo = getGroupKeyContent(dataId, group);
320+
String configInfo = getGroupKeyContent(dataId, group, true);
313321
String refreshTargetKey = beanName + "#method#" + methodSignature(method);
314322
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
315323
if (currentTarget != null) {
@@ -433,23 +441,23 @@ private void handleFiledNacosConfigAnnotation(NacosConfig annotation, String bea
433441
String key = annotation.key();
434442
try {
435443
ReflectionUtils.makeAccessible(field);
436-
handleFiledNacosConfigAnnotationInner(dataId, group, key, beanName, bean, field, annotation.defaultValue());
444+
handleFiledNacosConfigAnnotationInner(dataId, group, key, annotation.refreshed(), beanName, bean, field, annotation.defaultValue());
437445
}
438446
catch (Exception e) {
439447
throw new RuntimeException(e);
440448
}
441449
}
442450

443-
private void handleFiledNacosConfigAnnotationInner(String dataId, String group, String key, String beanName, Object bean,
451+
private void handleFiledNacosConfigAnnotationInner(String dataId, String group, String key, boolean refreshed, String beanName, Object bean,
444452
Field field, String defaultValue) {
445453
try {
446-
String config = getDestContent(getGroupKeyContent(dataId, group), key);
454+
String config = getDestContent(getGroupKeyContent(dataId, group, refreshed), key);
447455
if (!org.springframework.util.StringUtils.hasText(config)) {
448456
config = defaultValue;
449457
}
450458

451459
//primitive type
452-
if (handPrimitiveFiled(field, dataId, group, config, key, defaultValue, beanName, bean)) {
460+
if (handPrimitiveFiled(field, dataId, group, config, key, defaultValue, refreshed, beanName, bean)) {
453461
return;
454462
}
455463

@@ -461,6 +469,11 @@ private void handleFiledNacosConfigAnnotationInner(String dataId, String group,
461469
}
462470

463471
String refreshTargetKey = beanName + "#filed#" + field.getName();
472+
473+
if (!refreshed) {
474+
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
475+
return;
476+
}
464477
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
465478
if (currentTarget != null) {
466479
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
@@ -530,7 +543,7 @@ public String toString() {
530543
}
531544
}
532545

533-
private boolean handPrimitiveFiled(Field field, String dataId, String group, String config, String key, String defaultValue, String beanName, Object bean) throws Exception {
546+
private boolean handPrimitiveFiled(Field field, String dataId, String group, String config, String key, String defaultValue, boolean refreshed, String beanName, Object bean) throws Exception {
534547
if (field.getType().isPrimitive()) {
535548

536549
if (org.springframework.util.StringUtils.hasText(config)) {
@@ -543,6 +556,11 @@ private boolean handPrimitiveFiled(Field field, String dataId, String group, Str
543556
}
544557

545558
String refreshTargetKey = beanName + "#filed#" + field.getName();
559+
if (!refreshed) {
560+
log.info("[Nacos Config] refresh is set to false,do not register listener for {} to bean {} ", refreshTargetKey, bean);
561+
return true;
562+
}
563+
546564
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
547565
if (currentTarget != null) {
548566
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
@@ -729,7 +747,7 @@ private void handleMethodAnnotation(final Object bean, String beanName, final Me
729747
String group = (String) stringObjectMap.get("group");
730748
String key = (String) stringObjectMap.get("key");
731749
String defaultValue = (String) stringObjectMap.get("defaultValue");
732-
handleBeanNacosConfigAnnotation(dataId, group, key, beanName, bean, defaultValue);
750+
handleBeanNacosConfigAnnotation(dataId, group, key, true, beanName, bean, defaultValue);
733751
}
734752
}
735753

spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/NacosConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@
3939
String key() default "";
4040

4141
String defaultValue() default "";
42+
43+
boolean refreshed() default true;
4244
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2013-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.alibaba.cloud.nacos.proxy.druid;
18+
19+
import java.io.StringReader;
20+
import java.util.HashSet;
21+
import java.util.Iterator;
22+
import java.util.Map;
23+
import java.util.Properties;
24+
import java.util.Set;
25+
26+
import com.alibaba.cloud.nacos.NacosConfigManager;
27+
import com.alibaba.cloud.nacos.utils.StringUtils;
28+
import com.alibaba.druid.filter.FilterAdapter;
29+
import com.alibaba.druid.pool.DruidDataSource;
30+
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
31+
import com.alibaba.nacos.api.config.ConfigService;
32+
import com.alibaba.nacos.api.config.listener.AbstractListener;
33+
import com.alibaba.nacos.api.exception.NacosException;
34+
35+
public class NacosDruidConfigFilter extends FilterAdapter {
36+
37+
private final static String groupMatched = "nacos-datasource";
38+
39+
private final Set<String> idempotentControl = new HashSet<>();
40+
41+
private final String proxyDataId;
42+
43+
public NacosDruidConfigFilter(String proxyDataId) {
44+
this.proxyDataId = proxyDataId;
45+
}
46+
47+
@Override
48+
public void init(final DataSourceProxy dataSourceProxy) {
49+
50+
if (!(dataSourceProxy instanceof DruidDataSource)) {
51+
return;
52+
}
53+
String name = StringUtils.isNotBlank(dataSourceProxy.getName()) ? dataSourceProxy.getName()
54+
: String.valueOf(dataSourceProxy.hashCode());
55+
if (idempotentControl.contains(name)) {
56+
return;
57+
}
58+
59+
DruidDataSource druidDataSource = ((DruidDataSource) dataSourceProxy);
60+
ConfigService configService = NacosConfigManager.getInstance().getConfigService();
61+
62+
try {
63+
String druidProperties = configService.getConfig(proxyDataId, groupMatched, 3000L);
64+
Properties propertiesNew = convert(druidProperties);
65+
druidDataSource.configFromProperties(propertiesNew);
66+
}
67+
catch (Exception e) {
68+
throw new RuntimeException(e);
69+
}
70+
71+
//register listeners
72+
try {
73+
configService.addListener(proxyDataId, groupMatched, new AbstractListener() {
74+
@Override
75+
public void receiveConfigInfo(String configInfo) {
76+
try {
77+
Properties propertiesNew = convert(configInfo);
78+
79+
//refresh
80+
((DruidDataSource) dataSourceProxy).configFromProperties(propertiesNew);
81+
}
82+
catch (Exception e) {
83+
throw new RuntimeException(e);
84+
}
85+
}
86+
});
87+
}
88+
catch (NacosException e) {
89+
throw new RuntimeException(e);
90+
}
91+
idempotentControl.add(name);
92+
}
93+
94+
private static final String druidPrefix = "spring.datasource.druid.";
95+
96+
private static final String datasourcePrefix = "spring.datasource.";
97+
98+
private static Properties convert(String config) throws Exception {
99+
100+
Properties properties = new Properties();
101+
properties.load(new StringReader(config));
102+
103+
Properties propertiesNew = new Properties();
104+
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
105+
while (iterator.hasNext()) {
106+
Map.Entry<Object, Object> entry = iterator.next();
107+
String key = entry.getKey().toString();
108+
String value = entry.getValue().toString();
109+
110+
if (key.startsWith(druidPrefix)) {
111+
propertiesNew.put(key.replace(druidPrefix, "druid."), value);
112+
}
113+
else if (key.startsWith(datasourcePrefix)) {
114+
propertiesNew.put(key.replace(datasourcePrefix, "druid."), value);
115+
}
116+
}
117+
118+
return propertiesNew;
119+
}
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2013-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.alibaba.cloud.nacos.proxy.druid;
18+
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.core.env.Environment;
23+
24+
@Configuration
25+
public class NacosDruidFilterConfiguration {
26+
27+
@Bean
28+
@ConditionalOnProperty(value = "spring.nacos.config.proxy.druid.enabled", havingValue = "true")
29+
public NacosDruidConfigFilter nacosDruidFilter(Environment environment) {
30+
String proxyDataId = environment.getProperty("spring.nacos.config.proxy.druid.data-id");
31+
return new NacosDruidConfigFilter(proxyDataId);
32+
}
33+
34+
}

0 commit comments

Comments
 (0)