Skip to content

Commit effabf4

Browse files
authored
nacos config support type and bean factory (#3899)
1 parent d93217f commit effabf4

File tree

2 files changed

+153
-9
lines changed

2 files changed

+153
-9
lines changed

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

+152-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.alibaba.cloud.nacos.annotation;
1818

19+
import java.beans.PropertyDescriptor;
1920
import java.lang.reflect.Field;
2021
import java.lang.reflect.Method;
2122
import java.lang.reflect.Type;
@@ -37,12 +38,22 @@
3738
import org.slf4j.Logger;
3839
import org.slf4j.LoggerFactory;
3940

41+
import org.springframework.beans.BeanUtils;
42+
import org.springframework.beans.BeanWrapper;
43+
import org.springframework.beans.BeanWrapperImpl;
4044
import org.springframework.beans.BeansException;
45+
import org.springframework.beans.NotReadablePropertyException;
46+
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
47+
import org.springframework.beans.factory.config.BeanDefinition;
4148
import org.springframework.beans.factory.config.BeanPostProcessor;
4249
import org.springframework.context.ApplicationContext;
4350
import org.springframework.context.ApplicationContextAware;
51+
import org.springframework.context.support.GenericApplicationContext;
4452
import org.springframework.core.PriorityOrdered;
4553
import org.springframework.core.annotation.AnnotationUtils;
54+
import org.springframework.core.annotation.MergedAnnotation;
55+
import org.springframework.core.annotation.MergedAnnotations;
56+
import org.springframework.core.type.MethodMetadata;
4657
import org.springframework.util.ReflectionUtils;
4758

4859
public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware {
@@ -68,12 +79,12 @@ private String getGroupKeyContent(String dataId, String group) throws Exception
6879
}
6980
synchronized (this) {
7081
if (!groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
71-
String content = nacosConfigManager.getConfigService().getConfig(dataId, group, 5000);
82+
String content = getNacosConfigManager().getConfigService().getConfig(dataId, group, 5000);
7283
groupKeyCache.put(GroupKey.getKey(dataId, group), new AtomicReference<>(content));
7384

7485
log.info("[Nacos Config] Listening config for annotation: dataId={}, group={}", dataId,
7586
group);
76-
nacosConfigManager.getConfigService().addListener(dataId, group, new AbstractListener() {
87+
getNacosConfigManager().getConfigService().addListener(dataId, group, new AbstractListener() {
7788
@Override
7889
public void receiveConfigInfo(String s) {
7990
groupKeyCache.get(GroupKey.getKey(dataId, group)).set(s);
@@ -94,13 +105,20 @@ public String toString() {
94105

95106
@Override
96107
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
97-
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
108+
BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
109+
return bean;
98110
}
99111

100112
@Override
101113
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
102114
BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
103115
Class clazz = bean.getClass();
116+
NacosConfig annotationBean = AnnotationUtils.findAnnotation(clazz, NacosConfig.class);
117+
if (annotationBean != null) {
118+
handleBeanNacosConfigAnnotation(annotationBean.dataId(), annotationBean.group(), annotationBean.key(), beanName, bean, annotationBean.defaultValue());
119+
return bean;
120+
}
121+
104122
for (Field field : getBeanFields(clazz)) {
105123
handleFiledAnnotation(bean, beanName, field);
106124
}
@@ -129,6 +147,86 @@ private void handleFiledAnnotation(Object bean, String beanName, Field field) {
129147
}
130148
}
131149

150+
private void handleBeanNacosConfigAnnotation(String dataId, String group, String key, String beanName, Object bean,
151+
String defaultValue) {
152+
try {
153+
String config = getDestContent(getGroupKeyContent(dataId, group), key);
154+
if (!org.springframework.util.StringUtils.hasText(config)) {
155+
config = defaultValue;
156+
}
157+
//Init bean properties.
158+
if (org.springframework.util.StringUtils.hasText(config)) {
159+
Object targetObject = convertContentToTargetType(config, bean.getClass());
160+
//yaml and json to object
161+
BeanUtils.copyProperties(targetObject, bean, getNullPropertyNames(targetObject));
162+
}
163+
String refreshTargetKey = beanName + "#instance#";
164+
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
165+
if (currentTarget != null) {
166+
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
167+
currentTarget.getTarget(), bean);
168+
targetListenerMap.get(refreshTargetKey).setTarget(bean);
169+
return;
170+
}
171+
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
172+
bean);
173+
TargetRefreshable listener = null;
174+
if (org.springframework.util.StringUtils.hasText(key)) {
175+
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
176+
@Override
177+
public void configChanged(ConfigChangeEvent event) {
178+
try {
179+
ConfigChangeItem changeItem = event.getChangeItem(key);
180+
String newConfig = changeItem == null ? null : changeItem.getNewValue();
181+
if (!org.springframework.util.StringUtils.hasText(newConfig)) {
182+
newConfig = defaultValue;
183+
}
184+
if (org.springframework.util.StringUtils.hasText(newConfig)) {
185+
Object targetObject = convertContentToTargetType(newConfig, getTarget().getClass());
186+
//yaml and json to object
187+
BeanUtils.copyProperties(targetObject, getTarget(), getNullPropertyNames(targetObject));
188+
}
189+
}
190+
catch (Exception e) {
191+
throw new RuntimeException(e);
192+
}
193+
}
194+
195+
@Override
196+
public String toString() {
197+
return String.format("[spring cloud alibaba nacos config instance key listener , key %s , target %s ] ", key, bean);
198+
}
199+
};
200+
}
201+
else {
202+
listener = new NacosConfigRefreshableListener(bean) {
203+
@Override
204+
public void receiveConfigInfo(String configInfo) {
205+
if (!org.springframework.util.StringUtils.hasText(configInfo)) {
206+
configInfo = defaultValue;
207+
}
208+
if (org.springframework.util.StringUtils.hasText(configInfo)) {
209+
Object targetObject = convertContentToTargetType(configInfo, bean.getClass());
210+
//yaml and json to object
211+
BeanUtils.copyProperties(targetObject, getTarget());
212+
}
213+
}
214+
215+
@Override
216+
public String toString() {
217+
return String.format("[spring cloud alibaba nacos config instance listener , key %s , target %s ] ", key, bean);
218+
}
219+
};
220+
}
221+
getNacosConfigManager().getConfigService()
222+
.addListener(dataId, group, listener);
223+
targetListenerMap.put(refreshTargetKey, listener);
224+
}
225+
catch (Exception e) {
226+
throw new RuntimeException(e);
227+
}
228+
}
229+
132230
private void handleMethodNacosConfigKeysChangeListener(NacosConfigKeysListener annotation, String beanName, Object bean,
133231
Method method) {
134232
String dataId = annotation.dataId();
@@ -166,7 +264,7 @@ public String toString() {
166264
}
167265
};
168266
nacosPropertiesKeyListener.setLastContent(getGroupKeyContent(dataId, group));
169-
nacosConfigManager.getConfigService().addListener(dataId, group,
267+
getNacosConfigManager().getConfigService().addListener(dataId, group,
170268
nacosPropertiesKeyListener);
171269
targetListenerMap.put(refreshTargetKey, nacosPropertiesKeyListener);
172270
}
@@ -278,7 +376,7 @@ public String toString() {
278376
};
279377
}
280378

281-
nacosConfigManager.getConfigService().addListener(dataId, group, listener);
379+
getNacosConfigManager().getConfigService().addListener(dataId, group, listener);
282380
targetListenerMap.put(refreshTargetKey, listener);
283381
if (annotation.initNotify() && org.springframework.util.StringUtils.hasText(configInfo)) {
284382
try {
@@ -415,7 +513,7 @@ public String toString() {
415513
};
416514
}
417515

418-
nacosConfigManager.getConfigService()
516+
getNacosConfigManager().getConfigService()
419517
.addListener(dataId, group, listener);
420518
targetListenerMap.put(refreshTargetKey, listener);
421519

@@ -500,7 +598,7 @@ public String toString() {
500598
};
501599
}
502600

503-
nacosConfigManager.getConfigService()
601+
getNacosConfigManager().getConfigService()
504602
.addListener(dataId, group, listener);
505603
targetListenerMap.put(refreshTargetKey, listener);
506604
return true;
@@ -606,12 +704,58 @@ private void handleMethodAnnotation(final Object bean, String beanName, final Me
606704
handleMethodNacosConfigListener(configAnnotation, beanName, bean, method);
607705
return;
608706
}
707+
if (!applicationContext.containsBeanDefinition(beanName)) {
708+
return;
709+
}
710+
BeanDefinition beanDefinition = ((GenericApplicationContext) applicationContext).getBeanDefinition(beanName);
711+
if (beanDefinition instanceof AnnotatedBeanDefinition) {
712+
MethodMetadata factoryMethodMetadata = (((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata());
713+
if (factoryMethodMetadata != null) {
714+
MergedAnnotations annotations = factoryMethodMetadata.getAnnotations();
715+
if (annotations != null && annotations.isPresent(NacosConfig.class)) {
716+
MergedAnnotation<NacosConfig> nacosConfigMergedAnnotation = annotations.get(NacosConfig.class);
717+
Map<String, Object> stringObjectMap = nacosConfigMergedAnnotation.asMap();
718+
String dataId = (String) stringObjectMap.get("dataId");
719+
String group = (String) stringObjectMap.get("group");
720+
String key = (String) stringObjectMap.get("key");
721+
String defaultValue = (String) stringObjectMap.get("defaultValue");
722+
handleBeanNacosConfigAnnotation(dataId, group, key, beanName, bean, defaultValue);
723+
}
724+
}
725+
}
609726

610727
}
611728

612729
@Override
613730
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
614731
this.applicationContext = applicationContext;
615-
nacosConfigManager = this.applicationContext.getBean(NacosConfigManager.class);
616732
}
733+
734+
private NacosConfigManager getNacosConfigManager() {
735+
if (nacosConfigManager == null) {
736+
nacosConfigManager = this.applicationContext.getBean(NacosConfigManager.class);
737+
}
738+
return nacosConfigManager;
739+
}
740+
741+
private static String[] getNullPropertyNames(Object source) {
742+
final BeanWrapper src = new BeanWrapperImpl(source);
743+
PropertyDescriptor[] pds = src.getPropertyDescriptors();
744+
Set<String> nullPropertyNames = new HashSet<>();
745+
for (PropertyDescriptor pd : pds) {
746+
String propertyName = pd.getName();
747+
try {
748+
Object propertyValue = src.getPropertyValue(propertyName);
749+
if (propertyValue == null) {
750+
nullPropertyNames.add(propertyName);
751+
}
752+
}
753+
catch (NotReadablePropertyException e) {
754+
//ignore
755+
nullPropertyNames.add(propertyName);
756+
}
757+
}
758+
return nullPropertyNames.toArray(new String[0]);
759+
}
760+
617761
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* @author shiyiyue1102
2929
*/
3030
@Retention(RetentionPolicy.RUNTIME)
31-
@Target({ElementType.FIELD})
31+
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
3232
@Documented
3333
public @interface NacosConfig {
3434

0 commit comments

Comments
 (0)