|
|
|
@ -16,6 +16,7 @@
|
|
|
|
|
|
|
|
|
|
package com.alibaba.cloud.nacos.annotation;
|
|
|
|
|
|
|
|
|
|
import java.beans.PropertyDescriptor;
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.lang.reflect.Type;
|
|
|
|
@ -37,12 +38,22 @@ import com.alibaba.nacos.client.config.common.GroupKey;
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
|
import org.springframework.beans.BeanWrapper;
|
|
|
|
|
import org.springframework.beans.BeanWrapperImpl;
|
|
|
|
|
import org.springframework.beans.BeansException;
|
|
|
|
|
import org.springframework.beans.NotReadablePropertyException;
|
|
|
|
|
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
|
|
|
|
import org.springframework.beans.factory.config.BeanDefinition;
|
|
|
|
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
|
|
|
|
import org.springframework.context.ApplicationContext;
|
|
|
|
|
import org.springframework.context.ApplicationContextAware;
|
|
|
|
|
import org.springframework.context.support.GenericApplicationContext;
|
|
|
|
|
import org.springframework.core.PriorityOrdered;
|
|
|
|
|
import org.springframework.core.annotation.AnnotationUtils;
|
|
|
|
|
import org.springframework.core.annotation.MergedAnnotation;
|
|
|
|
|
import org.springframework.core.annotation.MergedAnnotations;
|
|
|
|
|
import org.springframework.core.type.MethodMetadata;
|
|
|
|
|
import org.springframework.util.ReflectionUtils;
|
|
|
|
|
|
|
|
|
|
public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware {
|
|
|
|
@ -68,12 +79,12 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
}
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
if (!groupKeyCache.containsKey(GroupKey.getKey(dataId, group))) {
|
|
|
|
|
String content = nacosConfigManager.getConfigService().getConfig(dataId, group, 5000);
|
|
|
|
|
String content = getNacosConfigManager().getConfigService().getConfig(dataId, group, 5000);
|
|
|
|
|
groupKeyCache.put(GroupKey.getKey(dataId, group), new AtomicReference<>(content));
|
|
|
|
|
|
|
|
|
|
log.info("[Nacos Config] Listening config for annotation: dataId={}, group={}", dataId,
|
|
|
|
|
group);
|
|
|
|
|
nacosConfigManager.getConfigService().addListener(dataId, group, new AbstractListener() {
|
|
|
|
|
getNacosConfigManager().getConfigService().addListener(dataId, group, new AbstractListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void receiveConfigInfo(String s) {
|
|
|
|
|
groupKeyCache.get(GroupKey.getKey(dataId, group)).set(s);
|
|
|
|
@ -94,13 +105,20 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
|
|
|
|
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
|
|
|
|
|
BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
|
|
|
|
|
return bean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
|
|
|
|
BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
|
|
|
|
Class clazz = bean.getClass();
|
|
|
|
|
NacosConfig annotationBean = AnnotationUtils.findAnnotation(clazz, NacosConfig.class);
|
|
|
|
|
if (annotationBean != null) {
|
|
|
|
|
handleBeanNacosConfigAnnotation(annotationBean.dataId(), annotationBean.group(), annotationBean.key(), beanName, bean, annotationBean.defaultValue());
|
|
|
|
|
return bean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Field field : getBeanFields(clazz)) {
|
|
|
|
|
handleFiledAnnotation(bean, beanName, field);
|
|
|
|
|
}
|
|
|
|
@ -129,6 +147,86 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleBeanNacosConfigAnnotation(String dataId, String group, String key, String beanName, Object bean,
|
|
|
|
|
String defaultValue) {
|
|
|
|
|
try {
|
|
|
|
|
String config = getDestContent(getGroupKeyContent(dataId, group), key);
|
|
|
|
|
if (!org.springframework.util.StringUtils.hasText(config)) {
|
|
|
|
|
config = defaultValue;
|
|
|
|
|
}
|
|
|
|
|
//Init bean properties.
|
|
|
|
|
if (org.springframework.util.StringUtils.hasText(config)) {
|
|
|
|
|
Object targetObject = convertContentToTargetType(config, bean.getClass());
|
|
|
|
|
//yaml and json to object
|
|
|
|
|
BeanUtils.copyProperties(targetObject, bean, getNullPropertyNames(targetObject));
|
|
|
|
|
}
|
|
|
|
|
String refreshTargetKey = beanName + "#instance#";
|
|
|
|
|
TargetRefreshable currentTarget = targetListenerMap.get(refreshTargetKey);
|
|
|
|
|
if (currentTarget != null) {
|
|
|
|
|
log.info("[Nacos Config] reset {} listener from {} to {} ", refreshTargetKey,
|
|
|
|
|
currentTarget.getTarget(), bean);
|
|
|
|
|
targetListenerMap.get(refreshTargetKey).setTarget(bean);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
log.info("[Nacos Config] register {} listener on {} ", refreshTargetKey,
|
|
|
|
|
bean);
|
|
|
|
|
TargetRefreshable listener = null;
|
|
|
|
|
if (org.springframework.util.StringUtils.hasText(key)) {
|
|
|
|
|
listener = new NacosPropertiesKeyListener(bean, wrapArrayToSet(key)) {
|
|
|
|
|
@Override
|
|
|
|
|
public void configChanged(ConfigChangeEvent event) {
|
|
|
|
|
try {
|
|
|
|
|
ConfigChangeItem changeItem = event.getChangeItem(key);
|
|
|
|
|
String newConfig = changeItem == null ? null : changeItem.getNewValue();
|
|
|
|
|
if (!org.springframework.util.StringUtils.hasText(newConfig)) {
|
|
|
|
|
newConfig = defaultValue;
|
|
|
|
|
}
|
|
|
|
|
if (org.springframework.util.StringUtils.hasText(newConfig)) {
|
|
|
|
|
Object targetObject = convertContentToTargetType(newConfig, getTarget().getClass());
|
|
|
|
|
//yaml and json to object
|
|
|
|
|
BeanUtils.copyProperties(targetObject, getTarget(), getNullPropertyNames(targetObject));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toString() {
|
|
|
|
|
return String.format("[spring cloud alibaba nacos config instance key listener , key %s , target %s ] ", key, bean);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
listener = new NacosConfigRefreshableListener(bean) {
|
|
|
|
|
@Override
|
|
|
|
|
public void receiveConfigInfo(String configInfo) {
|
|
|
|
|
if (!org.springframework.util.StringUtils.hasText(configInfo)) {
|
|
|
|
|
configInfo = defaultValue;
|
|
|
|
|
}
|
|
|
|
|
if (org.springframework.util.StringUtils.hasText(configInfo)) {
|
|
|
|
|
Object targetObject = convertContentToTargetType(configInfo, bean.getClass());
|
|
|
|
|
//yaml and json to object
|
|
|
|
|
BeanUtils.copyProperties(targetObject, getTarget());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toString() {
|
|
|
|
|
return String.format("[spring cloud alibaba nacos config instance listener , key %s , target %s ] ", key, bean);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
getNacosConfigManager().getConfigService()
|
|
|
|
|
.addListener(dataId, group, listener);
|
|
|
|
|
targetListenerMap.put(refreshTargetKey, listener);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleMethodNacosConfigKeysChangeListener(NacosConfigKeysListener annotation, String beanName, Object bean,
|
|
|
|
|
Method method) {
|
|
|
|
|
String dataId = annotation.dataId();
|
|
|
|
@ -166,7 +264,7 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
nacosPropertiesKeyListener.setLastContent(getGroupKeyContent(dataId, group));
|
|
|
|
|
nacosConfigManager.getConfigService().addListener(dataId, group,
|
|
|
|
|
getNacosConfigManager().getConfigService().addListener(dataId, group,
|
|
|
|
|
nacosPropertiesKeyListener);
|
|
|
|
|
targetListenerMap.put(refreshTargetKey, nacosPropertiesKeyListener);
|
|
|
|
|
}
|
|
|
|
@ -278,7 +376,7 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nacosConfigManager.getConfigService().addListener(dataId, group, listener);
|
|
|
|
|
getNacosConfigManager().getConfigService().addListener(dataId, group, listener);
|
|
|
|
|
targetListenerMap.put(refreshTargetKey, listener);
|
|
|
|
|
if (annotation.initNotify() && org.springframework.util.StringUtils.hasText(configInfo)) {
|
|
|
|
|
try {
|
|
|
|
@ -415,7 +513,7 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nacosConfigManager.getConfigService()
|
|
|
|
|
getNacosConfigManager().getConfigService()
|
|
|
|
|
.addListener(dataId, group, listener);
|
|
|
|
|
targetListenerMap.put(refreshTargetKey, listener);
|
|
|
|
|
|
|
|
|
@ -500,7 +598,7 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nacosConfigManager.getConfigService()
|
|
|
|
|
getNacosConfigManager().getConfigService()
|
|
|
|
|
.addListener(dataId, group, listener);
|
|
|
|
|
targetListenerMap.put(refreshTargetKey, listener);
|
|
|
|
|
return true;
|
|
|
|
@ -606,12 +704,58 @@ public class NacosAnnotationProcessor implements BeanPostProcessor, PriorityOrde
|
|
|
|
|
handleMethodNacosConfigListener(configAnnotation, beanName, bean, method);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!applicationContext.containsBeanDefinition(beanName)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
BeanDefinition beanDefinition = ((GenericApplicationContext) applicationContext).getBeanDefinition(beanName);
|
|
|
|
|
if (beanDefinition instanceof AnnotatedBeanDefinition) {
|
|
|
|
|
MethodMetadata factoryMethodMetadata = (((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata());
|
|
|
|
|
if (factoryMethodMetadata != null) {
|
|
|
|
|
MergedAnnotations annotations = factoryMethodMetadata.getAnnotations();
|
|
|
|
|
if (annotations != null && annotations.isPresent(NacosConfig.class)) {
|
|
|
|
|
MergedAnnotation<NacosConfig> nacosConfigMergedAnnotation = annotations.get(NacosConfig.class);
|
|
|
|
|
Map<String, Object> stringObjectMap = nacosConfigMergedAnnotation.asMap();
|
|
|
|
|
String dataId = (String) stringObjectMap.get("dataId");
|
|
|
|
|
String group = (String) stringObjectMap.get("group");
|
|
|
|
|
String key = (String) stringObjectMap.get("key");
|
|
|
|
|
String defaultValue = (String) stringObjectMap.get("defaultValue");
|
|
|
|
|
handleBeanNacosConfigAnnotation(dataId, group, key, beanName, bean, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
|
|
|
|
this.applicationContext = applicationContext;
|
|
|
|
|
nacosConfigManager = this.applicationContext.getBean(NacosConfigManager.class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private NacosConfigManager getNacosConfigManager() {
|
|
|
|
|
if (nacosConfigManager == null) {
|
|
|
|
|
nacosConfigManager = this.applicationContext.getBean(NacosConfigManager.class);
|
|
|
|
|
}
|
|
|
|
|
return nacosConfigManager;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String[] getNullPropertyNames(Object source) {
|
|
|
|
|
final BeanWrapper src = new BeanWrapperImpl(source);
|
|
|
|
|
PropertyDescriptor[] pds = src.getPropertyDescriptors();
|
|
|
|
|
Set<String> nullPropertyNames = new HashSet<>();
|
|
|
|
|
for (PropertyDescriptor pd : pds) {
|
|
|
|
|
String propertyName = pd.getName();
|
|
|
|
|
try {
|
|
|
|
|
Object propertyValue = src.getPropertyValue(propertyName);
|
|
|
|
|
if (propertyValue == null) {
|
|
|
|
|
nullPropertyNames.add(propertyName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (NotReadablePropertyException e) {
|
|
|
|
|
//ignore
|
|
|
|
|
nullPropertyNames.add(propertyName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullPropertyNames.toArray(new String[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|