Compare commits

..

39 Commits

Author SHA1 Message Date
W ce41f4d407
修复项目启动注入属性为null的空指针问题 (#357) 2025-06-09 19:59:46 +08:00
胡俊 bede11a7e2
update version 2.1.1 (#348) 2024-08-01 14:43:27 +08:00
abin 9388aa7f65
use nacos-spring-context self AbstractAnnotationBeanPostProcessor (#345) (#346) 2024-07-27 16:36:45 +08:00
Jefferson Chern 4b106fb992
resolve javadoc error. (#344)
* resolve javadoc error.

* add maven-war-plugin
2024-06-14 19:31:29 +08:00
胡俊 9b61ef68d2
update version 2.1.1-RC (#343) 2024-06-04 22:17:35 +08:00
Jefferson Chern 0a75c0b8c0
# 1.add guava in nacos-spring-context; (#342)
# 2.refactor dependency version.
2024-06-04 22:08:24 +08:00
W eb8b10f3f3
[ISSUE #285] Fix 服务端配置修改后,不支持@Value值的动态变更 #285 (#286)
* fix the thread-safety problem in NacosConfigurationPropertiesBinder (#268)

* 新增服务端配置更改后spring注解@Value值动态变更功能

---------

Co-authored-by: realJackSun <sjtusl@163.com>
Co-authored-by: 胡俊 <510830970@qq.com>
2024-05-09 23:27:48 +08:00
codestagea b209b291c2
修复 配置项value $符号异常 #293 (#317)
Co-authored-by: huijun.xu <huijun.xu@urbanic.com>
Co-authored-by: 胡俊 <510830970@qq.com>
2024-05-09 23:20:00 +08:00
pdkst fcf008405b
improve snakeyml compatibility for 2.2 (#336) 2024-05-09 23:11:27 +08:00
jsbxyyx 1ada9f4e88
fix: empty yaml npe (#332) 2023-12-18 20:55:36 +08:00
SuperZ1999 b1351d7f88
Summer (#331)
* [ISSUE #321] Support spring 6.x (#324)

* [ISSUE #315] Support spring 6.x

* Update document (#325)

* Modify version

---------

Co-authored-by: hujun3 <hujun3@xiaomi.com>
2023-12-03 13:05:31 +08:00
SuperZ1999 96d08e679d
Summer ospp#10375 (#330)
[ISSUE #321] Support spring 6.x (#324)
2023-12-03 11:50:51 +08:00
阿魁 5f0eb0b0d9
[ISSUE #314]Fix the RCE caused by the vulnerability in YAML deseriali… (#328)
* [ISSUE #314]Fix the RCE caused by the vulnerability in YAML deserialization.

* [ISSUE #314]Add YAML_ALLOW_OBJECT.

* [ISSUE #314]Add README.md.

* update style.

* Update.

* Update README.md
2023-11-22 14:32:17 +08:00
SuperZ1999 0e660eb3ab
Update document (#323) 2023-09-30 20:09:37 +08:00
SuperZ1999 d4543ecb97
[ISSUE #321] Support spring 6.x and native-image (#322)
* [ISSUE #315] Support spring 6.x

* Support native-image
2023-09-30 20:09:02 +08:00
zhanghong e8cae2c501
修改nacos-client 2.2.1版本,适配 (#307) 2023-05-10 11:40:20 +08:00
Akitata 9591915028
fixbug: error default field name (#303)
Co-authored-by: akitata <akitata@akitata>
2023-03-24 16:54:46 +08:00
qxo 4a99227a88
[ISSUE #269]去除每次构建时不必要的warning信息, 增加构建稳定性和性能 (#270)
指定构建依赖plugin的具体版本号
目的增加构建稳定性和性能
2022-09-30 21:42:30 +08:00
胡俊 13f14239ea
Merge pull request #295 from hujun-w-2/fix_code_merge
[ISSUE#296]develop branch merge
2022-09-30 21:30:37 +08:00
hujun3 1118b4bf2c Merge remote-tracking branch 'upstream/release1.1.1' into fix_code_merge 2022-09-30 15:40:53 +08:00
Oliver 4854adbe89
update README (#282) 2022-04-24 09:45:31 +08:00
胡俊 00072db454
Code optimization (#279)
* fix #7546

* Code optimization

* Code optimization
2022-02-10 10:20:48 +08:00
胡俊 26fee8ca46
Json parse bug (#280)
* fix #7546

* json parse bug
2022-01-24 16:09:47 +08:00
胡俊 31507dbf3f
fix #7546 (#276) 2022-01-11 17:40:46 +08:00
realJackSun 72f20b8f91 Release 1.1.1, fix the thread-safety problem in NacosConfigurationPropertiesBinder 2021-07-15 01:59:15 +08:00
brotherlu-xcq 3f0a06d6db
[ISSUE #238] optimize the property printout (#257)
* don't print the password in log file

* optimize the symbol

Co-authored-by: chenglu <tingqiu@qunhemail.com>
2021-06-21 11:37:24 +08:00
realJackSun 88741f1750
Merge pull request #263 from horizonzy/262-patch
Patch #262, add unit case.
2021-06-17 17:02:43 +08:00
horizonzy bd3b9652f3 patch for #262: append unit test. 2021-06-16 21:34:20 +08:00
zxn-git 8bfd91ff28
json默认值解析失败修复 (#262)
* json默认值解析失败修复

* json默认值解析失败修复 #262
2021-06-16 20:55:24 +08:00
邪影oO 01308b6b1b
Upgrade version number to 1.1.0 (#255) 2021-04-15 15:29:53 +08:00
邪影oO f906491e0a
增加 UT 时的文件编码(解决UT中有中文会乱码的问题) (#254) 2021-04-15 10:15:25 +08:00
小水牛 458517f414
issue#271 (#251)
NacosUtils.readFromEnvironment 支持基于 Environment 的 SeEL 表达式解析
同时增加 NacosUtils.readFromBeanFactory 方法支持基于 BeanFactory 的 SpEL 表达式解析
2021-04-14 11:26:35 +08:00
邪影oO 6a72c2966f
fix #5316 (#253) 2021-04-13 18:10:04 +08:00
邪影oO 400b3480f8
Merge pull request #250 from dmsolr/patch-1
fix delegate to the wrong method
2021-03-29 11:35:27 +08:00
Daming f791545562
fix typo 2021-03-24 15:07:08 +08:00
邪影oO d61ba1761b
Fix read type from data (#248)
* fix #247

* 默认配制类型改为 properties, test全部跑通

* 修改 license

* 修改CI问题
2021-03-05 09:49:29 +08:00
onewe 478e043739
[ISSUE-#243] fix weblogic classloader leak (#244)
* fix(AbstractNacosPropertySourceBuilder): 修复weblogic中classloader泄漏问题

- AbstractNacosPropertySourceBuilder增加销毁方法,关闭nacos相关线程池

* fix(AbstractNacosPropertySourceBuilder): 格式化代码

* fix(AbstractNacosPropertySourceBuilder): 格式化代码
2021-01-06 15:16:53 +08:00
Mercy Ma cddc2a329a
Merge pull request #237 from horizonzy/fix-236
[ISSUE-#236] Support spel expression
2020-10-28 13:54:22 +08:00
horizonzy a320f02179 support spel expression 2020-10-25 21:24:32 +08:00
82 changed files with 3095 additions and 639 deletions

1
.gitignore vendored
View File

@ -36,3 +36,4 @@ classes
*.prefs
*~
.extract
.flattened-pom.xml

View File

@ -41,6 +41,7 @@ Content
- [4.1.1. Enable Nacos](#411-enable-nacos)
- [4.1.2. Configure Change Listener method](#412-configure-change-listener-method)
- [4.1.2.1. Type Conversion](#4121-type-conversion)
- [4.1.2.1.1. Type Conversion during YAML Parsing](#41211-Type Conversion during YAML Parsing)
- [4.1.2.2. Timeout of Execution](#4122-timeout-of-execution)
- [4.1.3. Global and Special Nacos Properties](#413-global-and-special-nacos-properties)
- [4.1.4. `@NacosProperties`](#414-nacosproperties)
@ -95,7 +96,7 @@ The following table shows the dependencies and compatabilities of Nacos Spring P
| Dependencies | Compatibility |
| -------------- | ------------- |
| Java | 1.6+ |
| Java | 1.8+ |
| Spring Context | 3.2+ |
| [Alibaba Spring Context Support](https://github.com/alibaba/spring-context-support) | 1.0.1+ |
| [Alibaba Nacos](https://github.com/alibaba/nacos) | 1.1.1+ |
@ -123,14 +124,14 @@ Complete the following steps to enable Nacos for your Spring project.
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</dependency>
...
</dependencies>
```
**Note:** Support Spring 5 from version 0.2.3-RC1.
**Note:** Support Spring 5 from version 0.2.3-RC1, support Spring 6 from version 2.1.0.
2. Add the `@EnableNacos` annotation in the `@Configuration` class of Spring and specify "\${host}:${port}" of your Nacos server in the `serverAddr` attribute:
@ -315,8 +316,33 @@ The `UserNacosConfigConverter` class binds the `@NacosConfigListener.converter()
}
```
##### 4.1.2.1.1. Type Conversion during YAML Parsing
By default, starting from version 1.1.2, this library uses `SafeConstructor` for type conversion during YAML parsing. This is done to ensure that potentially unsafe code is not executed during the parsing process. `SafeConstructor` provides a secure construction logic for mapping YAML structures to Java objects.
**System Property Toggle**
To maintain compatibility with versions prior to 1.1.2, we have introduced a system property toggle named `yamlAllowComplexObject`. Prior to version 1.1.2, the library defaulted to using `Constructor`, another constructor in the SnakeYAML library that supports more complex object mapping. Starting from version 1.1.2, the default is switched to `SafeConstructor`.
**Potential Risks**
It's important to note that enabling `Constructor` introduces some potential risks, particularly the risk of Remote Code Execution (`RCE`). This is because `Constructor` allows more flexible object construction, but it also increases the risk of handling malicious YAML input.
**Recommendations**
- We recommend using the `NacosConfigConverter` for custom conversions.
**If You Must Use `Constructor`**
- Ensure that the source of the YAML data is secure.
**How to Disable `SafeConstructor`**
You can set the toggle by adding a JVM system property when starting your application. For example, in the command line:
```bash
java -DyamlAllowComplexObject=true -jar your-application.jar
```
- See [Type Conversion Sample of `@NacosConfigListener`](https://github.com/nacos-group/nacos-spring-project/blob/master/nacos-spring-samples/nacos-spring-webmvc-sample/src/main/java/com/alibaba/nacos/samples/spring/listener/PojoNacosConfigListener.java)

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context-aot</artifactId>
<version>${revision}</version>
<name>Alibaba Nacos :: Spring :: Context :: Aot</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring6.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring6.framework.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,76 @@
/*
*
* * 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 com.alibaba.nacos.spring.aot;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* {@link NacosInjected} and {@link NacosValue} AotProcessor
* The fields annotated with {@link NacosInjected} or {@link NacosValue} must be added to the reflect-config.json
* @author SuperZ1999
*/
public class NacosAnnotationBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
List<Field> fields = new ArrayList<>();
ReflectionUtils.doWithFields(beanClass, field -> {
NacosInjected injectedAnnotation = field.getDeclaredAnnotation(NacosInjected.class);
NacosValue nacosValueAnnotation = field.getDeclaredAnnotation(NacosValue.class);
if (injectedAnnotation != null || nacosValueAnnotation != null) {
fields.add(field);
}
});
if (fields.isEmpty()) {
return null;
}
return new AotContribution(fields);
}
private static class AotContribution implements BeanRegistrationAotContribution {
private final List<Field> fields;
public AotContribution() {
this.fields = new ArrayList<>();
}
public AotContribution(List<Field> fields) {
this.fields = fields;
}
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
for (Field field : fields) {
generationContext.getRuntimeHints().reflection().registerField(field);
}
}
}
}

View File

@ -0,0 +1,15 @@
{
"resources": {
"includes": [
{
"pattern": "\\QMETA-INF/spring.handlers\\E"
},
{
"pattern": "\\QMETA-INF/spring.schemas\\E"
},
{
"pattern": "\\QMETA-INF/schemas/nacos.xsd\\E"
}
]
}
}

View File

@ -0,0 +1,2 @@
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
com.alibaba.nacos.spring.aot.NacosAnnotationBeanRegistrationAotProcessor

View File

@ -5,57 +5,62 @@
<parent>
<artifactId>nacos-spring-parent</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.0.0</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.0.0</version>
<version>${revision}</version>
<name>Alibaba Nacos :: Spring :: Context</name>
<packaging>jar</packaging>
<dependencies>
<!-- java-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation-api.version}</version>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!--yaml-->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snake.yaml.version}</version>
</dependency>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Spring Context Extras -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>${project.groupId}</groupId>
@ -63,22 +68,27 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,644 @@
/*
* 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 com.alibaba.nacos.spring.beans.factory.annotation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAnnotationAttributes;
import static java.util.Collections.unmodifiableMap;
import static org.springframework.aop.support.AopUtils.getTargetClass;
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;
import static org.springframework.core.GenericTypeResolver.resolveTypeArgument;
/**
* Abstract common {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 1.0.3
*/
@SuppressWarnings("unchecked")
public abstract class AbstractAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
private final static int CACHE_SIZE = Integer.getInteger("", 32);
private final Log logger = LogFactory.getLog(getClass());
private final Class<? extends Annotation>[] annotationTypes;
private final ConcurrentMap<String, AnnotatedInjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, AnnotatedInjectionMetadata>(CACHE_SIZE);
private final ConcurrentMap<String, Object> injectedObjectsCache = new ConcurrentHashMap<String, Object>(CACHE_SIZE);
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader classLoader;
/**
* make sure higher priority than {@link AutowiredAnnotationBeanPostProcessor}
*/
private int order = Ordered.LOWEST_PRECEDENCE - 3;
/**
* whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
*
* @since 1.0.11
*/
private boolean classValuesAsString = true;
/**
* whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
*
* @since 1.0.11
*/
private boolean nestedAnnotationsAsMap = true;
/**
* whether ignore default value or not
*
* @since 1.0.11
*/
private boolean ignoreDefaultValue = true;
/**
* whether try merged annotation or not
*
* @since 1.0.11
*/
private boolean tryMergedAnnotation = true;
/**
* @param annotationTypes the multiple types of {@link Annotation annotations}
*/
public AbstractAnnotationBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
this.annotationTypes = annotationTypes;
}
private static <T> Collection<T> combine(Collection<? extends T>... elements) {
List<T> allElements = new ArrayList<T>();
for (Collection<? extends T> e : elements) {
allElements.addAll(e);
}
return allElements;
}
/**
* Annotation type
*
* @return non-null
* @deprecated 2.7.3, uses {@link #getAnnotationTypes()}
*/
@Deprecated
public final Class<? extends Annotation> getAnnotationType() {
return annotationTypes[0];
}
protected final Class<? extends Annotation>[] getAnnotationTypes() {
return annotationTypes;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
"AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
/**
* Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated fields
*
* @param beanClass The {@link Class} of Bean
* @return non-null {@link List}
*/
private List<AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AnnotatedFieldElement> elements = new LinkedList<AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(field, annotationType);
if (attributes != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
}
return;
}
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
}
});
return elements;
}
/**
* Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated methods
*
* @param beanClass The {@link Class} of Bean
* @return non-null {@link List}
*/
private List<AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
final List<AnnotatedMethodElement> elements = new LinkedList<AnnotatedMethodElement>();
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = findBridgedMethod(method);
if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(bridgedMethod, annotationType);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " annotation should only be used on methods with parameters: " +
method);
}
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
elements.add(new AnnotatedMethodElement(method, pd, attributes));
}
}
}
});
return elements;
}
/**
* Get {@link AnnotationAttributes}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>
* @since 1.0.11
*/
protected AnnotationAttributes doGetAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType) {
return getAnnotationAttributes(annotatedElement, annotationType, getEnvironment(),
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, tryMergedAnnotation);
}
private AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
Collection<AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
Collection<AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
"] for annotation metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public void destroy() throws Exception {
for (Object object : injectedObjectsCache.values()) {
if (logger.isInfoEnabled()) {
logger.info(object + " was destroying!");
}
if (object instanceof DisposableBean) {
((DisposableBean) object).destroy();
}
}
injectionMetadataCache.clear();
injectedObjectsCache.clear();
if (logger.isInfoEnabled()) {
logger.info(getClass() + " was destroying!");
}
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected Environment getEnvironment() {
return environment;
}
protected ClassLoader getClassLoader() {
return classLoader;
}
protected ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* Gets all injected-objects.
*
* @return non-null {@link Collection}
*/
protected Collection<Object> getInjectedObjects() {
return this.injectedObjectsCache.values();
}
/**
* Get injected-object from specified {@link AnnotationAttributes annotation attributes} and Bean Class
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return An injected object
* @throws Exception If getting is failed
*/
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
Object injectedObject = injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
if (injectedObject != null) {
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
}
return injectedObject;
}
/**
* Subclass must implement this method to get injected-object. The context objects could help this method if
* necessary :
* <ul>
* <li>{@link #getBeanFactory() BeanFactory}</li>
* <li>{@link #getClassLoader() ClassLoader}</li>
* <li>{@link #getEnvironment() Environment}</li>
* </ul>
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return The injected object
* @throws Exception If resolving an injected object is failed.
*/
protected abstract Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception;
/**
* Build a cache key for injected-object. The context objects could help this method if
* necessary :
* <ul>
* <li>{@link #getBeanFactory() BeanFactory}</li>
* <li>{@link #getClassLoader() ClassLoader}</li>
* <li>{@link #getEnvironment() Environment}</li>
* </ul>
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return Bean cache key
*/
protected abstract String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName,
Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement);
/**
* Get {@link Map} in injected field.
*
* @return non-null ready-only {@link Map}
*/
protected Map<InjectionMetadata.InjectedElement, Object> getInjectedFieldObjectsMap() {
Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
for (AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
Collection<AnnotatedFieldElement> fieldElements = metadata.getFieldElements();
for (AnnotatedFieldElement fieldElement : fieldElements) {
injectedElementBeanMap.put(fieldElement, fieldElement.bean);
}
}
return unmodifiableMap(injectedElementBeanMap);
}
/**
* Get {@link Map} in injected method.
*
* @return non-null {@link Map}
*/
protected Map<InjectionMetadata.InjectedElement, Object> getInjectedMethodObjectsMap() {
Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
for (AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
Collection<AnnotatedMethodElement> methodElements = metadata.getMethodElements();
for (AnnotatedMethodElement methodElement : methodElements) {
injectedElementBeanMap.put(methodElement, methodElement.object);
}
}
return unmodifiableMap(injectedElementBeanMap);
}
/**
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @since 1.0.11
*/
public void setClassValuesAsString(boolean classValuesAsString) {
this.classValuesAsString = classValuesAsString;
}
/**
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @since 1.0.11
*/
public void setNestedAnnotationsAsMap(boolean nestedAnnotationsAsMap) {
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
/**
* @param ignoreDefaultValue whether ignore default value or not
* @since 1.0.11
*/
public void setIgnoreDefaultValue(boolean ignoreDefaultValue) {
this.ignoreDefaultValue = ignoreDefaultValue;
}
/**
* @param tryMergedAnnotation whether try merged annotation or not
* @since 1.0.11
*/
public void setTryMergedAnnotation(boolean tryMergedAnnotation) {
this.tryMergedAnnotation = tryMergedAnnotation;
}
/**
* {@link Annotation Annotated} {@link InjectionMetadata} implementation
*/
private class AnnotatedInjectionMetadata extends InjectionMetadata {
private final Collection<AnnotatedFieldElement> fieldElements;
private final Collection<AnnotatedMethodElement> methodElements;
public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotatedFieldElement> fieldElements,
Collection<AnnotatedMethodElement> methodElements) {
super(targetClass, combine(fieldElements, methodElements));
this.fieldElements = fieldElements;
this.methodElements = methodElements;
}
public Collection<AnnotatedFieldElement> getFieldElements() {
return fieldElements;
}
public Collection<AnnotatedMethodElement> getMethodElements() {
return methodElements;
}
}
/**
* {@link Annotation Annotated} {@link Method} {@link InjectionMetadata.InjectedElement}
*/
private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
private final Method method;
private final AnnotationAttributes attributes;
private volatile Object object;
protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes) {
super(method, pd);
this.method = method;
this.attributes = attributes;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = pd.getPropertyType();
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(method);
method.invoke(bean, injectedObject);
}
}
/**
* {@link Annotation Annotated} {@link Field} {@link InjectionMetadata.InjectedElement}
*/
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
private final Field field;
private final AnnotationAttributes attributes;
private volatile Object bean;
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {
super(field, null);
this.field = field;
this.attributes = attributes;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = resolveInjectedType(bean, field);
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
}
private Class<?> resolveInjectedType(Object bean, Field field) {
Type genericType = field.getGenericType();
if (genericType instanceof Class) { // Just a normal Class
return field.getType();
} else { // GenericType
return resolveTypeArgument(getTargetClass(bean), field.getDeclaringClass());
}
}
}
}

View File

@ -34,7 +34,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
import com.alibaba.spring.util.BeanUtils;

View File

@ -39,16 +39,9 @@ import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NacosBeanDefinitionRegistrar.class)
@Import({NacosBeanDefinitionRegistrar.class, EnableNacosAotProcessor.class})
public @interface EnableNacos {
/**
* Whether to get the file type from dataId
*
* @return read config-type from dataId, default value is {@link Boolean#TRUE}
*/
boolean readConfigTypeFromDataId() default true;
/**
* Global {@link NacosProperties Nacos Properties}
*

View File

@ -0,0 +1,96 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Collection;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacos} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacos.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacos.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacos.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
registerNacosConfigListenerExecutor(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(this.beanFactory);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -36,8 +36,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* Nacos Properties {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar}
*
@ -66,9 +64,6 @@ public class NacosBeanDefinitionRegistrar
.fromMap(importingClassMetadata
.getAnnotationAttributes(EnableNacos.class.getName()));
boolean readTypeFromDataId = attributes.getBoolean("readConfigTypeFromDataId");
NacosUtils.setReadTypeFromDataIdIfNull(readTypeFromDataId);
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);

View File

@ -54,7 +54,7 @@ import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NacosConfigBeanDefinitionRegistrar.class)
@Import({NacosConfigBeanDefinitionRegistrar.class, EnableNacosConfigAotProcessor.class})
public @interface EnableNacosConfig {
/**
@ -141,13 +141,6 @@ public @interface EnableNacosConfig {
String PASSWORD_PLACEHOLDER = "${" + CONFIG_PREFIX + PASSWORD + ":"
+ NacosProperties.PASSWORD_PLACEHOLDER + "}";
/**
* Whether to get the file type from dataId
*
* @return read config-type from dataId, default value is {@link Boolean#TRUE}
*/
boolean readConfigTypeFromDataId() default true;
/**
* Global {@link NacosProperties Nacos Properties}
*

View File

@ -0,0 +1,95 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacosConfig} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosConfigBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosConfigBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosConfigAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacosConfig.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacosConfig.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacosConfig.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
registerNacosConfigListenerExecutor(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(this.beanFactory);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -35,7 +35,6 @@ import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotationMetadata;
import com.alibaba.nacos.spring.util.NacosBeanUtils;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* Nacos Config {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar}
@ -62,9 +61,6 @@ public class NacosConfigBeanDefinitionRegistrar
AnnotationAttributes attributes = fromMap(
metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));
boolean readTypeFromDataId = attributes.getBoolean("readConfigTypeFromDataId");
NacosUtils.setReadTypeFromDataIdIfNull(readTypeFromDataId);
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);

View File

@ -26,6 +26,7 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
@ -97,14 +98,14 @@ public class NacosConfigListenerMethodProcessor
environment);
final String groupId = NacosUtils.readFromEnvironment(listener.groupId(),
environment);
final String type;
if (NacosUtils.isReadTypeFromDataId()) {
ConfigType typeEnum = listener.type();
if (ConfigType.UNSET.equals(typeEnum)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = listener.type().getType();
type = typeEnum.getType();
}
long timeout = listener.timeout();
@ -170,21 +171,6 @@ public class NacosConfigListenerMethodProcessor
applicationEventPublisher.publishEvent(metadataEvent);
}
private ConfigService resolveConfigService(Properties nacosProperties,
ApplicationContext applicationContext) throws BeansException {
ConfigService configService = null;
try {
configService = nacosServiceFactory.createConfigService(nacosProperties);
}
catch (NacosException e) {
throw new BeanCreationException(e.getErrMsg(), e);
}
return configService;
}
@Override
protected boolean isCandidateMethod(Object bean, Class<?> beanClass,
NacosConfigListener listener, Method method,

View File

@ -162,7 +162,7 @@ public @interface NacosPropertySource {
*
* @return the type of config
*/
ConfigType type() default ConfigType.PROPERTIES;
ConfigType type() default ConfigType.UNSET;
/**
* The {@link NacosProperties} attribute, If not specified, it will use

View File

@ -28,6 +28,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.nacos.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@ -35,6 +37,8 @@ import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
@ -46,7 +50,6 @@ import org.springframework.util.ReflectionUtils;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import com.alibaba.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
/**
* Injected {@link NacosValue}
@ -65,10 +68,16 @@ public class NacosValueAnnotationBeanPostProcessor
*/
public static final String BEAN_NAME = "nacosValueAnnotationBeanPostProcessor";
private static final String SPEL_PREFIX = "#{";
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private static final char PLACEHOLDER_MATCH_PREFIX = '{';
private static final char PLACEHOLDER_MATCH_SUFFIX = '}';
private static final String VALUE_SEPARATOR = ":";
private final Logger logger = LoggerFactory.getLogger(getClass());
@ -82,6 +91,10 @@ public class NacosValueAnnotationBeanPostProcessor
private Environment environment;
private BeanExpressionResolver exprResolver;
private BeanExpressionContext exprContext;
public NacosValueAnnotationBeanPostProcessor() {
super(NacosValue.class);
}
@ -93,6 +106,8 @@ public class NacosValueAnnotationBeanPostProcessor
"NacosValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
this.exprResolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
this.exprContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
@Override
@ -104,10 +119,8 @@ public class NacosValueAnnotationBeanPostProcessor
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String annotationValue = attributes.getString("value");
String value = beanFactory.resolveEmbeddedValue(annotationValue);
Member member = injectedElement.getMember();
Object value = resolveStringValue(attributes.getString("value"));
Member member = injectedElement.getMember();
if (member instanceof Field) {
return convertIfNecessary((Field) member, value);
}
@ -146,6 +159,7 @@ public class NacosValueAnnotationBeanPostProcessor
.entrySet()) {
String key = environment.resolvePlaceholders(entry.getKey());
String newValue = environment.getProperty(key);
if (newValue == null) {
continue;
}
@ -155,17 +169,31 @@ public class NacosValueAnnotationBeanPostProcessor
boolean isUpdate = !target.lastMD5.equals(md5String);
if (isUpdate) {
target.updateLastMD5(md5String);
Object evaluatedValue = resolveNotifyValue(target.nacosValueExpr, key, newValue);
if (target.method == null) {
setField(target, newValue);
setField(target, evaluatedValue);
}
else {
setMethod(target, newValue);
setMethod(target, evaluatedValue);
}
}
}
}
}
private Object resolveNotifyValue(String nacosValueExpr, String key, String newValue) {
String spelExpr = StringUtils.replace(nacosValueExpr, PLACEHOLDER_PREFIX + key + PLACEHOLDER_SUFFIX, newValue);
return resolveStringValue(spelExpr);
}
private Object resolveStringValue(String strVal) {
String value = beanFactory.resolveEmbeddedValue(strVal);
if (exprResolver != null && value != null) {
return exprResolver.evaluate(value, exprContext);
}
return value;
}
private Object convertIfNecessary(Field field, Object value) {
TypeConverter converter = beanFactory.getTypeConverter();
return converter.convertIfNecessary(value, field.getType(), field);
@ -229,7 +257,7 @@ public class NacosValueAnnotationBeanPostProcessor
}
NacosValueTarget nacosValueTarget = new NacosValueTarget(bean, beanName,
method, field);
method, field, annotation.value());
put2ListMap(placeholderNacosValueTargetMap, placeholder,
nacosValueTarget);
}
@ -237,7 +265,7 @@ public class NacosValueAnnotationBeanPostProcessor
}
private String resolvePlaceholder(String placeholder) {
if (!placeholder.startsWith(PLACEHOLDER_PREFIX)) {
if (!placeholder.startsWith(PLACEHOLDER_PREFIX) && !placeholder.startsWith(SPEL_PREFIX)) {
return null;
}
@ -249,9 +277,15 @@ public class NacosValueAnnotationBeanPostProcessor
+ PLACEHOLDER_SUFFIX.length()) {
return null;
}
int beginIndex = PLACEHOLDER_PREFIX.length();
int endIndex = placeholder.length() - PLACEHOLDER_PREFIX.length() + 1;
int beginIndex = placeholder.indexOf(PLACEHOLDER_PREFIX);
if (beginIndex == -1) {
return null;
}
beginIndex = beginIndex + PLACEHOLDER_PREFIX.length();
int endIndex = placeholder.indexOf(PLACEHOLDER_SUFFIX, beginIndex);
if (endIndex == -1) {
return null;
}
placeholder = placeholder.substring(beginIndex, endIndex);
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
@ -271,7 +305,7 @@ public class NacosValueAnnotationBeanPostProcessor
map.put(key, valueList);
}
private void setMethod(NacosValueTarget nacosValueTarget, String propertyValue) {
private void setMethod(NacosValueTarget nacosValueTarget, Object propertyValue) {
Method method = nacosValueTarget.method;
ReflectionUtils.makeAccessible(method);
try {
@ -292,7 +326,7 @@ public class NacosValueAnnotationBeanPostProcessor
}
private void setField(final NacosValueTarget nacosValueTarget,
final String propertyValue) {
final Object propertyValue) {
final Object bean = nacosValueTarget.bean;
Field field = nacosValueTarget.field;
@ -328,7 +362,9 @@ public class NacosValueAnnotationBeanPostProcessor
private String lastMD5;
NacosValueTarget(Object bean, String beanName, Method method, Field field) {
private final String nacosValueExpr;
NacosValueTarget(Object bean, String beanName, Method method, Field field, String nacosValueExpr) {
this.bean = bean;
this.beanName = beanName;
@ -338,6 +374,31 @@ public class NacosValueAnnotationBeanPostProcessor
this.field = field;
this.lastMD5 = "";
this.nacosValueExpr = resolveExpr(nacosValueExpr);
}
private String resolveExpr(String nacosValueExpr) {
try {
int replaceHolderBegin = nacosValueExpr.indexOf(PLACEHOLDER_PREFIX) + PLACEHOLDER_PREFIX.length();
int replaceHolderEnd = replaceHolderBegin;
for (int i = 0; replaceHolderEnd < nacosValueExpr.length(); replaceHolderEnd++) {
char ch = nacosValueExpr.charAt(replaceHolderEnd);
if (PLACEHOLDER_MATCH_PREFIX == ch) {
i++;
} else if (PLACEHOLDER_MATCH_SUFFIX == ch && --i == -1) {
break;
}
}
String replaceHolder = nacosValueExpr.substring(replaceHolderBegin, replaceHolderEnd);
int separatorIndex = replaceHolder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
return nacosValueExpr.substring(0, separatorIndex + replaceHolderBegin) + nacosValueExpr.substring(replaceHolderEnd);
}
return nacosValueExpr;
} catch (Exception e) {
throw new IllegalArgumentException("The expr format is illegal, expr: " + nacosValueExpr, e);
}
}
protected void updateLastMD5(String newMD5) {

View File

@ -0,0 +1,331 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import com.alibaba.nacos.spring.util.NacosUtils;
import com.alibaba.nacos.spring.util.PlaceholderHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
/**
* @author wuhaoqiang
* @since 1.1.2
**/
public class SpringValueAnnotationBeanPostProcessor
extends AbstractAnnotationBeanPostProcessor implements BeanFactoryAware,
EnvironmentAware, ApplicationListener<NacosConfigReceivedEvent> {
/**
* The name of {@link SpringValueAnnotationBeanPostProcessor} bean.
*/
public static final String BEAN_NAME = "StringValueAnnotationBeanPostProcessor";
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* placeholder, valueTarget.
*/
private Map<String, List<StringValueTarget>> placeholderStringValueTargetMap = new HashMap<String, List<StringValueTarget>>();
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private BeanExpressionResolver exprResolver;
private BeanExpressionContext exprContext;
public SpringValueAnnotationBeanPostProcessor() {
super(Value.class);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"StringValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
this.exprResolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
this.exprContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
Object value = resolveStringValue(attributes.getString("value"));
Member member = injectedElement.getMember();
if (member instanceof Field) {
return convertIfNecessary((Field) member, value);
}
if (member instanceof Method) {
return convertIfNecessary((Method) member, value);
}
return null;
}
@Override
protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes,
Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
return bean.getClass().getName() + attributes;
}
@Override
public Object postProcessBeforeInitialization(Object bean, final String beanName)
throws BeansException {
doWithFields(bean, beanName);
doWithMethods(bean, beanName);
return super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public void onApplicationEvent(NacosConfigReceivedEvent event) {
if (StringUtils.isEmpty(event)) {
return;
}
Map<String, Object> updateProperties = NacosUtils.toProperties(event.getContent(), event.getType());
for (Map.Entry<String, List<StringValueTarget>> entry : placeholderStringValueTargetMap
.entrySet()) {
String key = environment.resolvePlaceholders(entry.getKey());
// Process modified keys, excluding deleted keys
if (!updateProperties.containsKey(key)) {
continue;
}
String newValue = environment.getProperty(key);
if (newValue == null) {
continue;
}
List<StringValueTarget> beanPropertyList = entry.getValue();
for (StringValueTarget target : beanPropertyList) {
String md5String = MD5Utils.md5Hex(newValue, "UTF-8");
boolean isUpdate = !target.lastMD5.equals(md5String);
if (isUpdate) {
target.updateLastMD5(md5String);
Object evaluatedValue = resolveStringValue(target.stringValueExpr);
if (target.method == null) {
setField(target, evaluatedValue);
} else {
setMethod(target, evaluatedValue);
}
}
}
}
}
private Object resolveStringValue(String strVal) {
String value = beanFactory.resolveEmbeddedValue(strVal);
if (exprResolver != null && value != null) {
return exprResolver.evaluate(value, exprContext);
}
return value;
}
private Object convertIfNecessary(Field field, Object value) {
TypeConverter converter = beanFactory.getTypeConverter();
return converter.convertIfNecessary(value, field.getType(), field);
}
private Object convertIfNecessary(Method method, Object value) {
Class<?>[] paramTypes = method.getParameterTypes();
Object[] arguments = new Object[paramTypes.length];
TypeConverter converter = beanFactory.getTypeConverter();
if (arguments.length == 1) {
return converter.convertIfNecessary(value, paramTypes[0],
new MethodParameter(method, 0));
}
for (int i = 0; i < arguments.length; i++) {
arguments[i] = converter.convertIfNecessary(value, paramTypes[i],
new MethodParameter(method, i));
}
return arguments;
}
private void doWithFields(final Object bean, final String beanName) {
ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException {
Value annotation = getAnnotation(field, Value.class);
doWithAnnotation(beanName, bean, annotation, field.getModifiers(),
null, field);
}
});
}
private void doWithMethods(final Object bean, final String beanName) {
ReflectionUtils.doWithMethods(bean.getClass(),
new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
Value annotation = getAnnotation(method, Value.class);
doWithAnnotation(beanName, bean, annotation,
method.getModifiers(), method, null);
}
});
}
private void doWithAnnotation(String beanName, Object bean, Value annotation,
int modifiers, Method method, Field field) {
if (annotation != null) {
if (Modifier.isStatic(modifiers)) {
return;
}
Set<String> placeholderList = PlaceholderHelper.findPlaceholderKeys(annotation.value());
for (String placeholder : placeholderList) {
StringValueTarget stringValueTarget = new StringValueTarget(bean, beanName,
method, field, annotation.value());
put2ListMap(placeholderStringValueTargetMap, placeholder,
stringValueTarget);
}
}
}
private <K, V> void put2ListMap(Map<K, List<V>> map, K key, V value) {
List<V> valueList = map.get(key);
if (valueList == null) {
valueList = new ArrayList<V>();
}
valueList.add(value);
map.put(key, valueList);
}
private void setMethod(StringValueTarget stringValueTarget, Object propertyValue) {
Method method = stringValueTarget.method;
ReflectionUtils.makeAccessible(method);
try {
method.invoke(stringValueTarget.bean,
convertIfNecessary(method, propertyValue));
if (logger.isDebugEnabled()) {
logger.debug("Update value with {} (method) in {} (bean) with {}",
method.getName(), stringValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value with " + method.getName()
+ " (method) in " + stringValueTarget.beanName + " (bean)", e);
}
}
}
private void setField(final StringValueTarget stringValueTarget,
final Object propertyValue) {
final Object bean = stringValueTarget.bean;
Field field = stringValueTarget.field;
String fieldName = field.getName();
try {
ReflectionUtils.makeAccessible(field);
field.set(bean, convertIfNecessary(field, propertyValue));
if (logger.isDebugEnabled()) {
logger.debug("Update value of the {}" + " (field) in {} (bean) with {}",
fieldName, stringValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value of the " + fieldName + " (field) in "
+ stringValueTarget.beanName + " (bean)", e);
}
}
}
private static class StringValueTarget {
private final Object bean;
private final String beanName;
private final Method method;
private final Field field;
private String lastMD5;
private final String stringValueExpr;
StringValueTarget(Object bean, String beanName, Method method, Field field, String stringValueExpr) {
this.bean = bean;
this.beanName = beanName;
this.method = method;
this.field = field;
this.lastMD5 = "";
this.stringValueExpr = stringValueExpr;
}
protected void updateLastMD5(String newMD5) {
this.lastMD5 = newMD5;
}
}
}

View File

@ -49,7 +49,7 @@ import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NacosDiscoveryBeanDefinitionRegistrar.class)
@Import({NacosDiscoveryBeanDefinitionRegistrar.class, EnableNacosDiscoveryAotProcessor.class})
public @interface EnableNacosDiscovery {
/**
* The prefix of property name of Nacos discovery

View File

@ -0,0 +1,92 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.discovery;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacosDiscovery} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosDiscoveryBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosDiscoveryBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosDiscoveryAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacosDiscovery.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacosDiscovery.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacosDiscovery.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerGlobalNacosProperties(attributes, registry, environment,
MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -24,7 +24,6 @@ import org.springframework.core.env.Environment;
import org.w3c.dom.Element;
import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* Nacos Annotation Driven {@link BeanDefinitionParser} for XML element
@ -39,9 +38,6 @@ public class NacosAnnotationDrivenBeanDefinitionParser implements BeanDefinition
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String val = element.getAttribute("read-type-from-daraId");
NacosUtils.setReadTypeFromDataIdIfNull("true".equalsIgnoreCase(val));
// Get Environment
Environment environment = parserContext.getDelegate().getReaderContext()
.getReader().getEnvironment();

View File

@ -26,8 +26,8 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
@ -54,7 +54,7 @@ import org.springframework.util.ReflectionUtils;
public abstract class AnnotationListenerMethodProcessor<A extends Annotation>
implements ApplicationListener<ContextRefreshedEvent> {
protected final Log logger = LogFactory.getLog(getClass());
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final Class<A> annotationType;
public AnnotationListenerMethodProcessor() {

View File

@ -16,12 +16,16 @@
*/
package com.alibaba.nacos.spring.context.event;
import com.alibaba.nacos.api.annotation.NacosProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import java.util.Iterator;
import java.util.Map;
/**
* Logging {@link NacosConfigMetadataEvent} {@link ApplicationListener}
*
@ -44,12 +48,48 @@ public class LoggingNacosConfigMetadataEventListener
@Override
public void onApplicationEvent(NacosConfigMetadataEvent event) {
if (logger.isInfoEnabled()) {
logger.info(LOGGING_MESSAGE, event.getDataId(), event.getGroupId(),
event.getBeanName(), event.getBean(), event.getBeanType(),
event.getAnnotatedElement(), event.getXmlResource(),
event.getNacosProperties(), event.getNacosPropertiesAttributes(),
event.getSource(), event.getTimestamp());
if (!logger.isInfoEnabled()) {
return;
}
logger.info(LOGGING_MESSAGE, event.getDataId(), event.getGroupId(),
event.getBeanName(), event.getBean(), event.getBeanType(),
event.getAnnotatedElement(), event.getXmlResource(),
obscuresNacosProperties(event.getNacosProperties()), event.getNacosPropertiesAttributes(),
event.getSource(), event.getTimestamp());
}
/**
* obscures some private field like password in {@link com.alibaba.nacos.api.annotation.NacosProperties}
* @param nacosProperties {@link com.alibaba.nacos.api.annotation.NacosProperties}
* @return the properties String after obscures
*/
private String obscuresNacosProperties(Map<Object, Object> nacosProperties) {
String nacosPropertyStr;
if (nacosProperties != null && nacosProperties.size() > 0) {
StringBuilder sb = new StringBuilder("{");
int size = nacosProperties.size();
int idx = 0;
for (Map.Entry<Object, Object> e : nacosProperties.entrySet()) {
Object key = e.getKey();
Object value = e.getValue();
sb.append(key);
sb.append('=');
// hide some private messages
if (key != null && NacosProperties.PASSWORD.equals(key.toString())) {
sb.append("******");
} else {
sb.append(value);
}
if (idx < size - 1) {
sb.append(", ");
}
idx ++;
}
sb.append("}");
nacosPropertyStr = sb.toString();
} else {
nacosPropertyStr = "{}";
}
return nacosPropertyStr;
}
}

View File

@ -114,6 +114,31 @@ public class EventPublishingConfigService
return published;
}
@Override
public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException {
boolean published = configService.publishConfig(dataId, group, content, type);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException {
boolean published = configService.publishConfigCas(dataId, group, content, casMd5);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type)
throws NacosException {
boolean published = configService.publishConfigCas(dataId, group, content, casMd5, type);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean removeConfig(String dataId, String group) throws NacosException {
boolean removed = configService.removeConfig(dataId, group);
@ -149,7 +174,7 @@ public class EventPublishingConfigService
/**
* Destroy lifecycle method to invoke {@link #shutDown()}
* @throws Exception
* @throws Exception throw exception
* @since 1.0.0
*/
@Override

View File

@ -103,12 +103,12 @@ public class NacosConfigurationPropertiesBinder {
environment);
final String type;
if (NacosUtils.isReadTypeFromDataId()) {
ConfigType typeEunm = properties.type();
if (ConfigType.UNSET.equals(typeEunm)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = (properties.yaml() ? ConfigType.YAML.getType()
: properties.type().getType());
type = typeEunm.getType();
}
final ConfigService configService = configServiceBeanBuilder
@ -117,6 +117,13 @@ public class NacosConfigurationPropertiesBinder {
// Add a Listener if auto-refreshed
if (properties.autoRefreshed()) {
String content = getContent(configService, dataId, groupId);
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, type, properties, content,
configService);
}
Listener listener = new AbstractListener() {
@Override
public void receiveConfigInfo(String config) {
@ -139,13 +146,6 @@ public class NacosConfigurationPropertiesBinder {
}
}
}
String content = getContent(configService, dataId, groupId);
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, type, properties, content,
configService);
}
}
protected void doBind(Object bean, String beanName, String dataId, String groupId,

View File

@ -35,6 +35,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@ -42,6 +43,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@ -68,7 +70,7 @@ import com.alibaba.nacos.spring.util.config.NacosConfigLoader;
*/
public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinition>
implements EnvironmentAware, BeanFactoryAware, BeanClassLoaderAware,
ApplicationContextAware, InitializingBean {
ApplicationContextAware, InitializingBean, DisposableBean {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Class<T> beanDefinitionType;
@ -163,14 +165,14 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
dataId = NacosUtils.readFromEnvironment(dataId, environment);
groupId = NacosUtils.readFromEnvironment(groupId, environment);
String type = null;
final String type;
if (NacosUtils.isReadTypeFromDataId()) {
ConfigType typeEunm = (ConfigType) runtimeAttributes.get(CONFIG_TYPE_ATTRIBUTE_NAME);
if (ConfigType.UNSET.equals(typeEunm)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = ((ConfigType) runtimeAttributes.get(CONFIG_TYPE_ATTRIBUTE_NAME))
.getType();
type = typeEunm.getType();
}
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes
@ -273,6 +275,17 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
globalNacosProperties = CONFIG.getMergedGlobalProperties(beanFactory);
}
@Override
public void destroy() throws Exception {
if (nacosConfigLoader == null) {
return;
}
ConfigService configService = nacosConfigLoader.getConfigService();
if (configService != null) {
configService.shutDown();
}
}
/**
* The type of {@link T Bean Definition}
*

View File

@ -29,8 +29,10 @@ import java.util.List;
import java.util.Properties;
import java.util.Set;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@ -80,15 +82,15 @@ public class NacosPropertySourcePostProcessor
*/
public static final String BEAN_NAME = "nacosPropertySourcePostProcessor";
private static BeanFactory beanFactory;
protected static BeanFactory beanFactory;
private final Set<String> processedBeanNames = new LinkedHashSet<String>();
protected final Set<String> processedBeanNames = new LinkedHashSet<String>();
private ConfigurableEnvironment environment;
private Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
protected Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
private ConfigServiceBeanBuilder configServiceBeanBuilder;
protected ConfigServiceBeanBuilder configServiceBeanBuilder;
public static void addListenerIfAutoRefreshed(
final NacosPropertySource nacosPropertySource, final Properties properties,
@ -170,7 +172,7 @@ public class NacosPropertySourcePostProcessor
}
private void processPropertySource(String beanName,
protected void processPropertySource(String beanName,
ConfigurableListableBeanFactory beanFactory) {
if (processedBeanNames.contains(beanName)) {
@ -179,6 +181,12 @@ public class NacosPropertySourcePostProcessor
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
doProcessPropertySource(beanName, beanDefinition);
processedBeanNames.add(beanName);
}
protected void doProcessPropertySource(String beanName, BeanDefinition beanDefinition) {
// Build multiple instance if possible
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(
beanName, beanDefinition);
@ -190,8 +198,6 @@ public class NacosPropertySourcePostProcessor
.resolveProperties(nacosPropertySource.getAttributesMetadata());
addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);
}
processedBeanNames.add(beanName);
}
private List<NacosPropertySource> buildNacosPropertySources(String beanName,

View File

@ -0,0 +1,105 @@
/*
* 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 com.alibaba.nacos.spring.enums;
import com.alibaba.nacos.common.utils.StringUtils;
/**
* Config file type enum.
*
*/
public enum FileTypeEnum {
/**
* Yaml file.
*/
YML("yaml"),
/**
* Yaml file.
*/
YAML("yaml"),
/**
* Text file.
*/
TXT("text"),
/**
* Text file.
*/
TEXT("text"),
/**
* Json file.
*/
JSON("json"),
/**
* Xml file.
*/
XML("xml"),
/**
* Html file.
*/
HTM("html"),
/**
* Html file.
*/
HTML("html"),
/**
* Properties file.
*/
PROPERTIES("properties");
/**
* File type corresponding to file extension.
*/
private String fileType;
FileTypeEnum(String fileType) {
this.fileType = fileType;
}
public String getFileType() {
return this.fileType;
}
/**
* Get the corresponding FileTypeEnum by file extension or fileType. If not found FileTypeEnum.TEXT is returned
*
* @param extOrFileType file extension or fileType
* @return return {@link FileTypeEnum}
*/
public static FileTypeEnum getFileTypeEnumByFileExtensionOrFileType(String extOrFileType) {
if (StringUtils.isNotBlank(extOrFileType)) {
String upperExtName = extOrFileType.trim().toUpperCase();
for (FileTypeEnum value : VALUES) {
if (value.name().equals(upperExtName)) {
return value;
}
}
}
return FileTypeEnum.PROPERTIES;
}
private static final FileTypeEnum[] VALUES = FileTypeEnum.values();
}

View File

@ -124,6 +124,11 @@ class DelegatingNamingMaintainService
delegate.updateService(service, selector);
}
@Override
public void shutDown() throws NacosException {
delegate.shutDown();
}
@Override
public Properties getProperties() {
return properties;

View File

@ -87,6 +87,18 @@ class DelegatingNamingService
delegate.registerInstance(serviceName, groupName, instance);
}
@Override
public void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
delegate.batchRegisterInstance(serviceName, groupName, instances);
}
@Override
public void batchDeregisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
delegate.batchDeregisterInstance(serviceName, groupName, instances);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port)
throws NacosException {
@ -114,7 +126,7 @@ class DelegatingNamingService
@Override
public void deregisterInstance(String serviceName, Instance instance)
throws NacosException {
delegate.registerInstance(serviceName, instance);
delegate.deregisterInstance(serviceName, instance);
}
@Override

View File

@ -92,7 +92,8 @@ public final class ConfigParseUtils {
if (DEFAULT_CONFIG_PARSE_MAP.containsKey(type)) {
ConfigParse configParse = DEFAULT_CONFIG_PARSE_MAP.get(type);
return configParse.parse(context);
Map<String, Object> parseMap = configParse.parse(context);
return parseMap == null ? new HashMap<>() : parseMap;
}
else {
throw new UnsupportedOperationException(

View File

@ -29,6 +29,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.nacos.spring.context.annotation.config.SpringValueAnnotationBeanPostProcessor;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
@ -362,6 +363,13 @@ public abstract class NacosBeanUtils {
NacosValueAnnotationBeanPostProcessor.class);
}
public static void registerStringValueAnnotationBeanPostProcessor(
BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
SpringValueAnnotationBeanPostProcessor.BEAN_NAME,
SpringValueAnnotationBeanPostProcessor.class);
}
/**
* Register Nacos Common Beans
*
@ -398,6 +406,8 @@ public abstract class NacosBeanUtils {
registerNacosValueAnnotationBeanPostProcessor(registry);
registerStringValueAnnotationBeanPostProcessor(registry);
registerConfigServiceBeanBuilder(registry);
registerLoggingNacosConfigMetadataEventListener(registry);

View File

@ -16,52 +16,43 @@
*/
package com.alibaba.nacos.spring.util;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import static org.springframework.util.StringUtils.hasText;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.api.config.annotation.NacosIgnore;
import com.alibaba.nacos.api.config.annotation.NacosProperty;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.enums.FileTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.expression.EnvironmentAccessor;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import static org.springframework.util.StringUtils.hasText;
/**
* Nacos Utilities class
@ -100,24 +91,18 @@ public abstract class NacosUtils {
private static final Set<Class<?>> NON_BEAN_CLASSES = Collections.unmodifiableSet(
new HashSet<Class<?>>(Arrays.asList(Object.class, Class.class)));
private static ExpressionParser parser = new SpelExpressionParser();
private static BeanExpressionResolver resolver = new StandardBeanExpressionResolver();
private static ConcurrentHashMap<String, Expression> expressionCache
= new ConcurrentHashMap();
private static ConcurrentHashMap<Environment, StandardEvaluationContext> environmentContextCache
= new ConcurrentHashMap();
private static final Logger logger = LoggerFactory.getLogger(NacosUtils.class);
private static Boolean readTypeFromDataId = null;
public static Boolean isReadTypeFromDataId() {
return readTypeFromDataId;
}
public static void setReadTypeFromDataIdIfNull(boolean readTypeFromDataId) {
if (NacosUtils.readTypeFromDataId == null) {
NacosUtils.readTypeFromDataId = readTypeFromDataId;
}
}
public static void resetReadTypeFromDataId() {
NacosUtils.readTypeFromDataId = null;
}
/**
* Build The default name of {@link NacosConfigurationProperties @NacosPropertySource}
*
@ -215,12 +200,51 @@ public abstract class NacosUtils {
}
public static String readFromEnvironment(String label, Environment environment) {
return environment.resolvePlaceholders(label);
String value = resolvePlaceholders(label, environment);
return StringUtils.hasText(value)
? evaluate(value, environment)
: value;
}
public static Object readFromBeanFactory(String label, ConfigurableBeanFactory beanFactory) {
if (beanFactory == null) {
return label;
}
String value = beanFactory.resolveEmbeddedValue(label);
return StringUtils.hasText(value) ? evaluate(value, beanFactory) : value;
}
public static String resolvePlaceholders(String label, Environment environment) {
return environment == null ? label : environment.resolvePlaceholders(label);
}
public static String evaluate(String value, Environment environment) {
Expression expression = expressionCache.get(value);
if (expression == null) {
expression = parser.parseExpression(value, new TemplateParserContext());
expressionCache.put(value, expression);
}
StandardEvaluationContext evaluationContext = environmentContextCache.get(environment);
if (evaluationContext == null) {
evaluationContext = new StandardEvaluationContext(environment);
evaluationContext.addPropertyAccessor(new EnvironmentAccessor());
environmentContextCache.put(environment, evaluationContext);
}
return expression.getValue(evaluationContext, String.class);
}
public static Object evaluate(String value, ConfigurableBeanFactory beanFactory) {
return resolver.evaluate(value, new BeanExpressionContext(beanFactory, null));
}
public static String readFileExtension(String dataId) {
int lastIndex = dataId.lastIndexOf(".");
return dataId.substring(lastIndex + 1);
final String extName = dataId.substring(lastIndex + 1);
FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(extName);
return fileTypeEnum.getFileType();
}
public static PropertyValues resolvePropertyValues(Object bean, String content,
@ -508,6 +532,7 @@ public abstract class NacosUtils {
* @param group config group
* @param text config context
* @param type config type
* @return map format of result
*/
public static Map<String, Object> toProperties(String dataId, String group,
String text, String type) {

View File

@ -0,0 +1,126 @@
package com.alibaba.nacos.spring.util;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.springframework.util.StringUtils;
import java.util.Set;
import java.util.Stack;
/**
* @author wuhaoqiang
* @since 1.1.2
**/
public class PlaceholderHelper {
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private static final String VALUE_SEPARATOR = ":";
private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
/**
* find keys from placeholder
* ${key} - "key"
* xxx${key}yyy - "key"
* ${key:${key2:1}} - "key", "key2"
* ${${key}} - "key"
* ${${key:100}} - "key"
* ${${key}:${key2}} - "key", "key2"
* @param propertyString ${key}
* @return key
*/
public static Set<String> findPlaceholderKeys(String propertyString) {
Set<String> placeholderKeys = Sets.newHashSet();
if (Strings.isNullOrEmpty(propertyString) ||
!(propertyString.contains(PLACEHOLDER_PREFIX) && propertyString.contains(PLACEHOLDER_SUFFIX))) {
return placeholderKeys;
}
// handle xxx${yyy}zzz -> ${yyy}zzz
propertyString = propertyString.substring(propertyString.indexOf(PLACEHOLDER_PREFIX));
Stack<String> stack = new Stack<String>();
stack.push(propertyString);
while (!stack.isEmpty()) {
String strVal = stack.pop();
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
placeholderKeys.add(strVal);
continue;
}
int endIndex = findPlaceholderEndIndex(strVal, startIndex);
if (endIndex == -1) {
// invalid placeholder
continue;
}
String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
// ${key}
// startsWith '${' continue
if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) {
stack.push(placeholderCandidate);
} else {
// exist ':' -> key:${key2:2}
int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR);
if (separatorIndex == -1) {
stack.push(placeholderCandidate);
} else {
stack.push(placeholderCandidate.substring(0, separatorIndex));
String defaultValuePart =
normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length()));
if (!Strings.isNullOrEmpty(defaultValuePart)) {
stack.push(defaultValuePart);
}
}
}
// has remaining part, e.g. ${a}.${b}
if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) {
String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length()));
if (!Strings.isNullOrEmpty(remainingPart)) {
stack.push(remainingPart);
}
}
}
return placeholderKeys;
}
private static String normalizeToPlaceholder(String strVal) {
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
return null;
}
int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX);
if (endIndex == -1) {
return null;
}
return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length());
}
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + PLACEHOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + PLACEHOLDER_SUFFIX.length();
} else {
return index;
}
} else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) {
withinNestedPlaceholder++;
index = index + SIMPLE_PLACEHOLDER_PREFIX.length();
} else {
index++;
}
}
return -1;
}
}

View File

@ -0,0 +1,44 @@
/*
*
* * 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 com.alibaba.nacos.spring.util.aot;
import org.springframework.core.SpringProperties;
public abstract class AotDetector {
/**
* System property that indicates the application should run with AOT
* generated artifacts. If such optimizations are not available, it is
* recommended to throw an exception rather than fall back to the regular
* runtime behavior.
*/
public static final String AOT_ENABLED = "spring.aot.enabled";
/**
* Determine whether AOT optimizations must be considered at runtime. This
* is mandatory in a native image but can be triggered on the JVM using
* the {@value #AOT_ENABLED} Spring property.
* @return whether AOT optimizations must be considered
*/
public static boolean useGeneratedArtifacts() {
return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_ENABLED));
}
}

View File

@ -0,0 +1,33 @@
/*
*
* * 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 com.alibaba.nacos.spring.util.aot;
public abstract class NativeDetector {
// See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
private static final boolean imageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
/**
* @return Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.
*/
public static boolean inNativeImage() {
return imageCode;
}
}

View File

@ -33,6 +33,7 @@ public class DefaultJsonConfigParse extends AbstractConfigParse {
@Override
public Map<String, Object> parse(String configText) {
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
configText = configText.replaceAll("\t", "");
DefaultYamlConfigParse.process(new DefaultYamlConfigParse.MatchCallback() {
@Override
public void process(Map<String, Object> map) {

View File

@ -394,7 +394,7 @@ public class DefaultPropertiesConfigParse extends AbstractConfigParse {
CharacterReader(Resource resource) throws IOException {
this.reader = new LineNumberReader(new InputStreamReader(
resource.getInputStream(), StandardCharsets.ISO_8859_1));
resource.getInputStream(), StandardCharsets.UTF_8));
}
@Override

View File

@ -17,24 +17,26 @@
package com.alibaba.nacos.spring.util.parse;
import java.util.AbstractMap;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.parser.ParserException;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
import java.util.regex.Pattern;
/**
* DefaultYamlConfigParse.
@ -44,171 +46,151 @@ import com.alibaba.nacos.spring.util.AbstractConfigParse;
*/
public class DefaultYamlConfigParse extends AbstractConfigParse {
protected static final Logger LOGGER = LoggerFactory
.getLogger(DefaultYamlConfigParse.class);
protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultYamlConfigParse.class);
protected static Yaml createYaml() {
return new Yaml(new MapAppenderConstructor());
}
private static final String YAML_ALLOW_COMPLEX_OBJECT = "yamlAllowComplexObject";
protected static boolean process(MatchCallback callback, Yaml yaml, String content) {
int count = 0;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loading from YAML: " + content);
}
for (Object object : yaml.loadAll(content)) {
if (object != null && process(asMap(object), callback)) {
count++;
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loaded " + count + " document" + (count > 1 ? "s" : "")
+ " from YAML resource: " + content);
}
return (count > 0);
}
private static boolean getYamlAllowComplexObject() {
return Boolean.getBoolean(YAML_ALLOW_COMPLEX_OBJECT);
}
protected static boolean process(Map<String, Object> map, MatchCallback callback) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Merging document (no matchers set): " + map);
}
callback.process(getFlattenedMap(map));
return true;
}
protected static Yaml createYaml() {
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
SafeConstructor constructor;
if (getYamlAllowComplexObject()) {
constructor = new Constructor(loaderOptions);
} else {
constructor = new SafeConstructor(loaderOptions);
}
DumperOptions dumperOptions = new DumperOptions();
Representer representer = new Representer(dumperOptions);
LimitedResolver resolver = new LimitedResolver();
return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
}
@SuppressWarnings("unchecked")
protected static Map<String, Object> asMap(Object object) {
// YAML can have numbers as keys
Map<String, Object> result = new LinkedHashMap();
if (!(object instanceof Map)) {
// A document can be a text literal
result.put("document", object);
return result;
}
protected static boolean process(MatchCallback callback, Yaml yaml, String content) {
int count = 0;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loading from YAML: " + content);
}
for (Object object : yaml.loadAll(content)) {
if (object != null && process(asMap(object), callback)) {
count++;
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") + " from YAML resource: " + content);
}
return (count > 0);
}
Map<Object, Object> map = (Map<Object, Object>) object;
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
value = asMap(value);
}
if (key instanceof CharSequence) {
result.put(key.toString(), value);
}
else {
result.put("[" + key.toString() + "]", value);
}
}
return result;
}
protected static boolean process(Map<String, Object> map, MatchCallback callback) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Merging document (no matchers set): " + map);
}
callback.process(getFlattenedMap(map));
return true;
}
protected static Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>();
buildFlattenedMap(result, source, null);
return result;
}
@SuppressWarnings("unchecked")
protected static Map<String, Object> asMap(Object object) {
// YAML can have numbers as keys
Map<String, Object> result = new LinkedHashMap();
if (!(object instanceof Map)) {
// A document can be a text literal
result.put("document", object);
return result;
}
protected static void buildFlattenedMap(Map<String, Object> result,
Map<String, Object> source, String path) {
for (Map.Entry<String, Object> entry : source.entrySet()) {
String key = entry.getKey();
if (!StringUtils.isBlank(path)) {
if (key.startsWith("[")) {
key = path + key;
}
else {
key = path + '.' + key;
}
}
Object value = entry.getValue();
if (value instanceof String) {
result.put(key, value);
}
else if (value instanceof Map) {
// Need a compound key
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) value;
buildFlattenedMap(result, map, key);
}
else if (value instanceof Collection) {
// Need a compound key
@SuppressWarnings("unchecked")
Collection<Object> collection = (Collection<Object>) value;
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result,
Collections.singletonMap("[" + (count++) + "]", object), key);
}
}
else {
result.put(key, (value != null ? value.toString() : ""));
}
}
}
Map<Object, Object> map = (Map<Object, Object>) object;
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
value = asMap(value);
}
if (key instanceof CharSequence) {
result.put(key.toString(), value);
} else {
result.put("[" + key.toString() + "]", value);
}
}
return result;
}
@Override
public Map<String, Object> parse(String configText) {
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
process(new MatchCallback() {
@Override
public void process(Map<String, Object> map) {
result.set(map);
}
}, createYaml(), configText);
return result.get();
}
private static class LimitedResolver extends Resolver {
@Override
public String processType() {
return ConfigType.YAML.getType();
}
@Override
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
if (tag == Tag.TIMESTAMP) {
return;
}
super.addImplicitResolver(tag, regexp, first);
}
}
protected interface MatchCallback {
protected static Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>();
buildFlattenedMap(result, source, null);
return result;
}
/**
* Put Map to Properties.
*
* @param map {@link Map}
*/
void process(Map<String, Object> map);
}
protected static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
for (Map.Entry<String, Object> entry : source.entrySet()) {
String key = entry.getKey();
if (!StringUtils.isBlank(path)) {
if (key.startsWith("[")) {
key = path + key;
} else {
key = path + '.' + key;
}
}
Object value = entry.getValue();
if (value instanceof String) {
result.put(key, value);
} else if (value instanceof Map) {
// Need a compound key
@SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) value;
buildFlattenedMap(result, map, key);
} else if (value instanceof Collection) {
// Need a compound key
@SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value;
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result, Collections.singletonMap("[" + (count++) + "]", object), key);
}
} else {
result.put(key, (value != null ? value.toString() : ""));
}
}
}
protected static class MapAppenderConstructor extends Constructor {
@Override
public Map<String, Object> parse(String configText) {
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
process(new MatchCallback() {
@Override
public void process(Map<String, Object> map) {
result.set(map);
}
}, createYaml(), configText);
return result.get();
}
MapAppenderConstructor() {
super();
}
@Override
public String processType() {
return ConfigType.YAML.getType();
}
@Override
protected Map<Object, Object> constructMapping(MappingNode node) {
try {
return super.constructMapping(node);
}
catch (IllegalStateException ex) {
throw new ParserException("while parsing MappingNode",
node.getStartMark(), ex.getMessage(), node.getEndMark());
}
}
protected interface MatchCallback {
@Override
protected Map<Object, Object> createDefaultMap() {
final Map<Object, Object> delegate = super.createDefaultMap();
return new AbstractMap<Object, Object>() {
@Override
public Object put(Object key, Object value) {
if (delegate.containsKey(key)) {
throw new IllegalStateException("Duplicate key: " + key);
}
return delegate.put(key, value);
}
@Override
public Set<Entry<Object, Object>> entrySet() {
return delegate.entrySet();
}
};
}
}
/**
* Put Map to Properties.
*
* @param map {@link Map}
*/
void process(Map<String, Object> map);
}
}

View File

@ -23,9 +23,6 @@
@NacosConfigProperties / @NacosProperty / @NacosIgnore
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="read-type-from-daraId" default="true"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="global-properties">
@ -38,7 +35,7 @@
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="endpoint" default="${nacos.endpoint:}"/>
<xsd:attribute name="namespace" default="${nacos.endpoint:}"/>
<xsd:attribute name="namespace" default="${nacos.namespace:}"/>
<xsd:attribute name="access-key" default="${nacos.access-key:}"/>
<xsd:attribute name="secret-key" default="${nacos.secret-key:}"/>
<xsd:attribute name="server-addr" default="${nacos.server-addr:}"/>

View File

@ -0,0 +1,52 @@
/*
*
* * 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 com.alibaba.nacos.spring.beans.factory.annotation;
import org.junit.Assert;
import org.junit.Test;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
/**
* {@link AbstractAnnotationBeanPostProcessor} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class AbstractAnnotationBeanPostProcessorTest {
@Test
public void testPropertyDescriptor() throws IntrospectionException {
PropertyDescriptor pd = new PropertyDescriptor("name", Student.class);
Class<?> type = pd.getPropertyType();
Assert.assertEquals(type, String.class);
}
static class Student {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -74,16 +74,6 @@ public class AnnotationNacosInjectedBeanPostProcessorTest
@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private NamingService namingService3;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Bean(name = ApplicationContextHolder.BEAN_NAME)
public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {

View File

@ -25,9 +25,7 @@ import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -48,7 +46,6 @@ import com.alibaba.nacos.spring.context.config.xml.NacosAnnotationDrivenBeanDefi
import com.alibaba.nacos.spring.context.config.xml.NacosNamespaceHandler;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.User;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* {@link NacosNamespaceHandler} Test
@ -64,7 +61,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@DirtiesContext
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosNamespaceHandlerTest.class })
@EnableNacos(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${nacos.server-addr}"))
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${nacos.server-addr}"))
public class NacosNamespaceHandlerTest
extends AbstractNacosHttpServerTestExecutionListener {
@Autowired
@ -72,16 +69,6 @@ public class NacosNamespaceHandlerTest
@NacosInjected
private ConfigService configService;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "nacos.server-addr";

View File

@ -69,7 +69,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosBeanDefinitionRegistrarTest.class })
@EnableNacos(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig
@EnableNacosDiscovery
public class NacosBeanDefinitionRegistrarTest
@ -125,11 +125,6 @@ public class NacosBeanDefinitionRegistrarTest
@Value("${user.home:${user.dir}}")
private String dir;
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";

View File

@ -42,7 +42,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NacosConfigBeanDefinitionRegistrarTest.class)
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@EnableNacosConfig(globalProperties = @NacosProperties(enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component
public class NacosConfigBeanDefinitionRegistrarTest {
@ -52,16 +52,6 @@ public class NacosConfigBeanDefinitionRegistrarTest {
@Qualifier(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties properties;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Test
public void testRegisterBeanDefinitions() {

View File

@ -66,7 +66,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosConfigListenerMethodProcessorTest.class })
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosConfigListenerMethodProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -76,16 +76,6 @@ public class NacosConfigListenerMethodProcessorTest
private ConfigService configService;
private volatile boolean received = false;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Bean(name = ApplicationContextHolder.BEAN_NAME)
public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {

View File

@ -62,16 +62,6 @@ public class NacosConfigListenerTest
@NacosInjected
private ConfigService configService;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
@ -129,7 +119,7 @@ public class NacosConfigListenerTest
@Configuration
// 在命名空间详情处可以获取到 endpoint namespaceaccessKey secretKey 推荐使用 RAM 账户的
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public static class NacosConfiguration {
}

View File

@ -35,16 +35,6 @@ import com.alibaba.nacos.spring.util.NacosUtils;
*/
public class NacosPropertiesTest {
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Test
public void testConstants() {
Assert.assertEquals("nacos.", NacosProperties.PREFIX);

View File

@ -56,7 +56,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
DirtiesContextTestExecutionListener.class, NacosPropertySourceBeanTest.class })
@NacosPropertySources(value = { @NacosPropertySource(dataId = YamlBean.DATA_ID_YAML
+ ".yml", autoRefreshed = true) })
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosPropertySourceBeanTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -70,16 +70,6 @@ public class NacosPropertySourceBeanTest
@Autowired
private YamlBean yamlBean;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);

View File

@ -0,0 +1,39 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.config;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
/**
* {@link NacosPropertySourceBuilder} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class NacosPropertySourceBuilderTest {
@Test
public void test() {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
Assert.assertNotNull(propertySource);
}
}

View File

@ -58,7 +58,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosPropertySourceJsonTest.class })
@NacosPropertySource(dataId = NacosPropertySourceJsonTest.DATA_ID, autoRefreshed = true, type = ConfigType.JSON)
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosPropertySourceJsonTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -75,16 +75,6 @@ public class NacosPropertySourceJsonTest
@Autowired
private App app;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";

View File

@ -72,7 +72,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosPropertySourcePostProcessorTest.class })
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosPropertySourcePostProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -85,16 +85,6 @@ public class NacosPropertySourcePostProcessorTest
@NacosInjected
private ConfigService configService;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);

View File

@ -61,7 +61,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
DirtiesContextTestExecutionListener.class,
NacosPropertySourceReadFromEnvironmentTest.class })
@NacosPropertySource(dataId = NacosPropertySourceReadFromEnvironmentTest.ENV_DATA_ID, groupId = ENV_GROUP_ID, autoRefreshed = true)
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component
public class NacosPropertySourceReadFromEnvironmentTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -83,16 +83,6 @@ public class NacosPropertySourceReadFromEnvironmentTest
@Autowired
private ConfigurableEnvironment environment;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@BeforeClass
public static void init() {
System.setProperty("data-id", "app.properties");

View File

@ -21,12 +21,17 @@ import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTE
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -40,15 +45,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* {@link NacosPropertySource} {@link Value} Test
*
@ -63,7 +59,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
DirtiesContextTestExecutionListener.class, NacosPropertySourceTest.class })
@NacosPropertySources({
@NacosPropertySource(dataId = NacosPropertySourceTest.DATA_ID, autoRefreshed = true) })
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component
public class NacosPropertySourceTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -76,6 +72,13 @@ public class NacosPropertySourceTest
private static final int VALUE_2 = 2;
private static final int VALUE_3 = 3;
private static final int VALUE_4 = 4;
private static final String VALUE_5 = "zhangsan";
private static final String VALUE_6 = "lisi";
private static final String VALUE_7 = "wangwu";
private static final String VALUE_8 = "zhaoliu";
private static final String DEFAULT_JSON_VALUE = "{\"0\":\"1\",\"10\":\"13\"}";
private static final String NEW_STR_VALUE = "new json value";
@NacosInjected
private ConfigService configService;
@Autowired
@ -83,16 +86,6 @@ public class NacosPropertySourceTest
@Autowired
private Environment environment;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);
@ -101,7 +94,8 @@ public class NacosPropertySourceTest
config.put(CONTENT_PARAM_NAME, "app.name=" + APP_NAME + LINE_SEPARATOR
+ "app.nacosFieldIntValueAutoRefreshed=" + VALUE_1 + LINE_SEPARATOR
+ "app.nacosMethodIntValueAutoRefreshed=" + VALUE_2);
+ "app.nacosMethodIntValueAutoRefreshed=" + VALUE_2 + LINE_SEPARATOR
+ "app.nacosFieldListValueAutoRefreshed=" + VALUE_5 + "," + VALUE_6);
httpServer.initConfig(config);
}
@ -133,13 +127,23 @@ public class NacosPropertySourceTest
Assert.assertEquals(VALUE_2, app.nacosMethodIntValue);
Assert.assertEquals(VALUE_5, app.nacosFieldListValue.get(0));
Assert.assertEquals(VALUE_6, app.nacosFieldListValue.get(1));
Assert.assertEquals(VALUE_1, app.nacosFieldIntValueAutoRefreshed);
Assert.assertEquals(VALUE_2, app.nacosMethodIntValueAutoRefreshed);
Assert.assertEquals(VALUE_5, app.nacosFieldListValueAutoRefreshed.get(0));
Assert.assertEquals(VALUE_6, app.nacosFieldListValueAutoRefreshed.get(1));
Assert.assertEquals(DEFAULT_JSON_VALUE, app.strWithDefaultJsonValue);
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "app.name=" + ANOTHER_APP_NAME
+ LINE_SEPARATOR + "app.nacosFieldIntValueAutoRefreshed=" + VALUE_3
+ LINE_SEPARATOR + "app.nacosMethodIntValueAutoRefreshed=" + VALUE_4);
+ LINE_SEPARATOR + "app.nacosMethodIntValueAutoRefreshed=" + VALUE_4
+ LINE_SEPARATOR + "app.nacosFieldListValueAutoRefreshed=" + VALUE_7 + "," + VALUE_8
+ LINE_SEPARATOR + "app.strWithDefaultJsonValue=" + NEW_STR_VALUE);
Thread.sleep(1000);
@ -159,9 +163,17 @@ public class NacosPropertySourceTest
Assert.assertEquals(VALUE_2, app.nacosMethodIntValue);
Assert.assertEquals(VALUE_5, app.nacosFieldListValue.get(0));
Assert.assertEquals(VALUE_6, app.nacosFieldListValue.get(1));
Assert.assertEquals(VALUE_3, app.nacosFieldIntValueAutoRefreshed);
Assert.assertEquals(VALUE_4, app.nacosMethodIntValueAutoRefreshed);
Assert.assertEquals(VALUE_7, app.nacosFieldListValueAutoRefreshed.get(0));
Assert.assertEquals(VALUE_8, app.nacosFieldListValueAutoRefreshed.get(1));
Assert.assertEquals(NEW_STR_VALUE, app.strWithDefaultJsonValue);
}
public static class App {
@ -190,6 +202,15 @@ public class NacosPropertySourceTest
private int nacosMethodIntValue;
private int nacosMethodIntValueAutoRefreshed;
@NacosValue(value = "#{'${app.nacosFieldListValue:" + VALUE_5 + "," + VALUE_6 + "}'.split(',')}")
private List nacosFieldListValue;
@NacosValue(value = "#{'${app.nacosFieldListValueAutoRefreshed}'.split(',')}", autoRefreshed = true)
private List nacosFieldListValueAutoRefreshed;
@NacosValue(value = "${app.strWithDefaultJsonValue:" + DEFAULT_JSON_VALUE + "}", autoRefreshed = true)
private String strWithDefaultJsonValue;
@NacosValue("${app.nacosMethodIntValue:" + VALUE_2 + "}")
public void setNacosMethodIntValue(int nacosMethodIntValue) {
this.nacosMethodIntValue = nacosMethodIntValue;

View File

@ -55,7 +55,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@ContextConfiguration(classes = { NacosPropertySourceXmlTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosPropertySourceXmlTest.class })
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"), readConfigTypeFromDataId = false)
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosPropertySourceXmlTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -71,16 +71,6 @@ public class NacosPropertySourceXmlTest
@Autowired
private XmlApp xmlApp;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";

View File

@ -81,12 +81,10 @@ public class NacosPropertySourceYamlTest
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override

View File

@ -0,0 +1,64 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.config;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.MethodParameter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.lang.reflect.Method;
/**
* {@link NacosValueAnnotationBeanPostProcessor} Test
* @author SuperZ1999
* @date 2023/9/28
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NacosValueAnnotationBeanPostProcessorTest.class)
public class NacosValueAnnotationBeanPostProcessorTest {
@Autowired
private ConfigurableListableBeanFactory beanFactory;
@Bean
public NacosValueAnnotationBeanPostProcessor nacosValueAnnotationBeanPostProcessor() {
return new NacosValueAnnotationBeanPostProcessor();
}
@Test
public void testConvertIfNecessary() throws NoSuchMethodException {
TypeConverter converter = beanFactory.getTypeConverter();
Method method = NacosValueAnnotationBeanPostProcessorTest.class.getMethod("testMethodParameter", Integer.class);
Integer integer = converter.convertIfNecessary("12", Integer.class, new MethodParameter(method, 0));
System.out.println(integer);
Assert.assertEquals(integer, Integer.valueOf(12));
}
public void testMethodParameter(Integer i) {
System.out.println(i);
}
}

View File

@ -43,7 +43,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@NacosPropertySource(dataId = "yaml_map"
+ "_not_exist.yaml", autoRefreshed = true),
@NacosPropertySource(dataId = "yaml_map" + ".yml", autoRefreshed = true) })
@EnableNacosConfig(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosYamlMapTest extends AbstractNacosHttpServerTestExecutionListener {
@ -58,16 +58,6 @@ public class NacosYamlMapTest extends AbstractNacosHttpServerTestExecutionListen
@NacosInjected
private ConfigService configService;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";

View File

@ -75,14 +75,8 @@ public class NacosAnnotationDrivenBeanDefinitionParserTest {
System.setProperty("nacos.server-addr", "127.0.0.1:8080");
}
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
System.getProperties().remove("nacos.server-addr");
}

View File

@ -65,16 +65,6 @@ public class NacosPropertySourceBeanDefinitionParserTest
@Autowired
private User user;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Override
protected void init(EmbeddedNacosHttpServer server) {
Map<String, String> config = new HashMap<String, String>(1);

View File

@ -0,0 +1,36 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.config.xml;
import org.junit.Assert;
import org.junit.Test;
/**
* {@link NacosPropertySourceXmlBeanDefinition} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class NacosPropertySourceXmlBeanDefinitionTest {
@Test
public void test() {
NacosPropertySourceXmlBeanDefinition beanDefinition = new NacosPropertySourceXmlBeanDefinition();
Assert.assertNotNull(beanDefinition);
}
}

View File

@ -0,0 +1,107 @@
package com.alibaba.nacos.spring.context.properties.config;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
/**
* Chinese in test configuration.
*
* @author klw(213539 @ qq.com)
* @date 2021/4/13 14:14
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ChineseConfigTest.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, ChineseConfigTest.class })
@NacosPropertySources(value = { @NacosPropertySource(dataId = ChineseConfigTest.DATA_ID, autoRefreshed = true) })
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component
public class ChineseConfigTest extends AbstractNacosHttpServerTestExecutionListener {
public static final String DATA_ID = "chinese-config-test";
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String CH1_VALUE= "测试111";
private static final String CH2_VALUE= "测试222";
@NacosInjected
private ConfigService configService;
@Autowired
private CfgBean cfgBean;
@Bean
public CfgBean cfgBean() {
return new CfgBean();
}
@Test
public void testValue() throws InterruptedException, NacosException {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "cfg.ch1=" + CH1_VALUE + LINE_SEPARATOR
+ "cfg.ch2=" + CH2_VALUE);
Thread.sleep(1000);
Assert.assertEquals(CH1_VALUE, cfgBean.ch1);
Assert.assertEquals(CH2_VALUE, cfgBean.ch2);
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);
config.put(DATA_ID_PARAM_NAME, DATA_ID);
config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP);
config.put(CONTENT_PARAM_NAME, "cfg.ch1=测试1" + LINE_SEPARATOR
+ "cfg.ch2=测试2");
httpServer.initConfig(config);
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@NacosConfigurationProperties(dataId = DATA_ID, autoRefreshed = true, type = ConfigType.PROPERTIES)
public class CfgBean {
@NacosValue(value = "${cfg.ch1:中文1}", autoRefreshed = true)
private String ch1;
@NacosValue(value = "${cfg.ch2:中文2}", autoRefreshed = true)
private String ch2;
}
}

View File

@ -0,0 +1,79 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.properties.config;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.validation.BindException;
import org.springframework.validation.DataBinder;
/**
* {@link DataBinder} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class DataBinderTest {
@Test
public void test() throws BindException {
People people = new People();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("name", "SuperZ1999");
propertyValues.add("age", 24);
DataBinder dataBinder = new DataBinder(people);
dataBinder.setAutoGrowNestedPaths(false);
dataBinder.setIgnoreInvalidFields(false);
dataBinder.setIgnoreUnknownFields(true);
dataBinder.bind(propertyValues);
dataBinder.close();
Assert.assertEquals("SuperZ1999", people.getName());
Assert.assertEquals(24, people.getAge());
}
static class People {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}

View File

@ -55,7 +55,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosConfigurationPropertiesBindingPostProcessorTest.class })
@EnableNacos(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosConfigurationPropertiesBindingPostProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -64,16 +64,6 @@ public class NacosConfigurationPropertiesBindingPostProcessorTest
@NacosInjected
private ConfigService configService;
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Bean
public Config config() {
return new Config();

View File

@ -58,7 +58,7 @@ import com.alibaba.nacos.spring.util.NacosUtils;
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
CacheableEventPublishingNacosServiceFactoryTest.class })
@EnableNacos(readConfigTypeFromDataId = false, globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class CacheableEventPublishingNacosServiceFactoryTest
extends AbstractNacosHttpServerTestExecutionListener {
@ -66,16 +66,6 @@ public class CacheableEventPublishingNacosServiceFactoryTest
private NacosServiceFactory nacosServiceFactory;
private Properties properties = new Properties();
@BeforeClass
public static void beforeClass() {
NacosUtils.resetReadTypeFromDataId();
}
@AfterClass
public static void afterClass() {
NacosUtils.resetReadTypeFromDataId();
}
@Bean(name = NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)
public static ExecutorService executorService() {
return Executors.newSingleThreadExecutor();

View File

@ -0,0 +1,40 @@
/*
*
* * 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 com.alibaba.nacos.spring.factory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Service;
import com.alibaba.nacos.client.naming.NacosNamingMaintainService;
import org.junit.Assert;
import org.junit.Test;
/**
* {@link DelegatingNamingMaintainService} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class DelegatingNamingMaintainServiceTest {
@Test
public void testNamingMaintainService() throws NacosException {
NacosNamingMaintainService namingMaintainService = new NacosNamingMaintainService("127.0.0.1:8848");
Service service = namingMaintainService.queryService("example");
Assert.assertNotNull(service);
}
}

View File

@ -0,0 +1,43 @@
/*
*
* * 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 com.alibaba.nacos.spring.factory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.NacosNamingService;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* {@link DelegatingNamingService} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class DelegatingNamingServiceTest {
@Test
public void testNamingService() throws NacosException {
NacosNamingService nacosNamingService = new NacosNamingService("127.0.0.1:8848");
List<Instance> instances = nacosNamingService.getAllInstances("example");
System.out.println(instances);
Assert.assertNotNull(instances);
}
}

View File

@ -98,6 +98,86 @@ public class MockConfigService implements ConfigService {
return true;
}
@Override
public boolean publishConfig(String dataId, String group, final String content, String type)
throws NacosException {
String key = createKey(dataId, group, type);
contentCache.put(key, content);
List<Listener> listeners = listenersCache.get(key);
if (!CollectionUtils.isEmpty(listeners)) {
for (final Listener listener : listeners) {
Executor executor = listener.getExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
listener.receiveConfigInfo(content);
}
});
}
else {
listener.receiveConfigInfo(content);
}
}
}
return true;
}
@Override
public boolean publishConfigCas(String dataId, String group, final String content, String casMd5) throws NacosException {
String key = createKey(dataId, group);
contentCache.put(key, content);
List<Listener> listeners = listenersCache.get(key);
if (!CollectionUtils.isEmpty(listeners)) {
for (final Listener listener : listeners) {
Executor executor = listener.getExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
listener.receiveConfigInfo(content);
}
});
}
else {
listener.receiveConfigInfo(content);
}
}
}
return true;
}
@Override
public boolean publishConfigCas(String dataId, String group, final String content, String casMd5, String type)
throws NacosException {
String key = createKey(dataId, group, type);
contentCache.put(key, content);
List<Listener> listeners = listenersCache.get(key);
if (!CollectionUtils.isEmpty(listeners)) {
for (final Listener listener : listeners) {
Executor executor = listener.getExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
listener.receiveConfigInfo(content);
}
});
}
else {
listener.receiveConfigInfo(content);
}
}
}
return true;
}
@Override
public boolean removeConfig(String dataId, String group) throws NacosException {
String key = createKey(dataId, group);
@ -123,4 +203,8 @@ public class MockConfigService implements ConfigService {
private String createKey(String dataId, String groupId) {
return dataId + "&" + groupId;
}
private String createKey(String dataId, String groupId, String type) {
return dataId + "&" + groupId + "&" + type;
}
}

View File

@ -26,6 +26,7 @@ import org.junit.Test;
import com.alibaba.nacos.spring.util.parse.DefaultPropertiesConfigParse;
import com.alibaba.nacos.spring.util.parse.DefaultYamlConfigParse;
import org.springframework.core.io.ByteArrayResource;
/**
* @author liaochuntao
@ -83,6 +84,13 @@ public class ConfigParseUtilsTest {
System.out.println(p);
}
@Test
public void testResource() {
ByteArrayResource resource = new ByteArrayResource(new byte[]{1, 1, 1, 1, 1, 1});
String description = resource.getDescription();
Assert.assertNotNull(description);
}
@Test
public void testYamlParser() {
final String yaml = "students:\n" + " - {name: lct-1,num: 12}\n"

View File

@ -20,6 +20,12 @@ import java.lang.reflect.Field;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ReflectionUtils;
import com.alibaba.nacos.api.annotation.NacosInjected;
@ -31,6 +37,8 @@ import com.alibaba.nacos.api.annotation.NacosProperties;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NacosUtilsTest.class)
public class NacosUtilsTest {
@NacosInjected
@ -39,6 +47,9 @@ public class NacosUtilsTest {
@NacosInjected(properties = @NacosProperties(serverAddr = "test"))
private Object object2 = new Object();
@Autowired
private ConfigurableBeanFactory beanFactory;
@Test
public void testIsDefault() {
@ -57,4 +68,17 @@ public class NacosUtilsTest {
Assert.assertEquals(expectedValue, NacosUtils.isDefault(nacosProperties));
}
@Test
public void testReadFromBeanFactory() {
Object o = NacosUtils.readFromBeanFactory("test", beanFactory);
Assert.assertEquals("test", o);
}
@Test
public void testMutablePropertyValues() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("testKey", "testValue");
Assert.assertEquals("testValue", propertyValues.get("testKey"));
}
}

View File

@ -1,37 +1,56 @@
package com.alibaba.nacos.spring.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.api.config.annotation.NacosIgnore;
import org.junit.Assert;
import org.junit.Test;
public class ObjectUtilsTest {
@Test
public void test_map_clean() {
TestObj obj = new TestObj();
Map<String, Object> map = new HashMap<String, Object>();
map.put("key", "value");
obj.setMap(map);
List<String> list = new ArrayList<>();
list.add("element");
obj.setList(list);
Assert.assertNotNull(map.get("key"));
Assert.assertNotNull(obj.map);
Assert.assertNotNull(obj.list);
ObjectUtils.cleanMapOrCollectionField(obj);
map = obj.map;
Assert.assertNull(map);
Assert.assertNull(obj.map);
Assert.assertNotNull(obj.list);
}
private static class TestObj {
private Map<String, Object> map;
@NacosIgnore
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}
}

View File

@ -0,0 +1,33 @@
package com.alibaba.nacos.spring.util;
import com.google.common.collect.Sets;
import org.junit.Assert;
import org.junit.Test;
/**
* @author whq
* @since 1.1.2
*/
public class PlaceholderHelperTest {
@Test
public void testFindPlaceholderKeys() {
/**
* find keys from placeholder
* ${key} => "key"
* xxx${key}yyy => "key"
* ${key:${key2:1}} => "key", "key2"
* ${${key}} => "key"
* ${${key:100}} => "key"
* ${${key}:${key2}} => "key", "key2"
*/
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("${key}"), Sets.newHashSet("key"));
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("xxx${key}yyy"), Sets.newHashSet("key"));
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("${key:${key2:1}}"), Sets.newHashSet("key", "key2"));
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("${${key}}"), Sets.newHashSet("key"));
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("${${key:100}}"), Sets.newHashSet("key"));
Assert.assertEquals(PlaceholderHelper.findPlaceholderKeys("${${key}:${key2}}"), Sets.newHashSet("key", "key2"));
}
}

View File

@ -16,14 +16,15 @@
*/
package com.alibaba.nacos.spring.util;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.annotation.NacosProperties;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.env.MockEnvironment;
/**
* {@link PropertiesPlaceholderResolver} Test
*
@ -31,26 +32,39 @@ import org.springframework.mock.env.MockEnvironment;
* @since 0.1.0
*/
public class PropertiesPlaceholderResolverTest {
@Test
public void testResolve() {
MockEnvironment environment = new MockEnvironment();
PropertiesPlaceholderResolver resolver = new PropertiesPlaceholderResolver(
environment);
testMapResolve(environment, resolver);
testAnnotationResolve(environment, resolver);
}
private void testMapResolve(MockEnvironment environment, PropertiesPlaceholderResolver resolver) {
Map properties = new HashMap();
properties.put("my.name", "${my.name}");
properties.put("my.age", 18);
environment.setProperty("my.name", "mercyblitz");
environment.setProperty("my.age", "18");
Properties resolvedProperties = resolver.resolve(properties);
Assert.assertEquals(resolvedProperties.get("my.name"), "mercyblitz");
Assert.assertNull(resolvedProperties.get("my.age"));
}
private void testAnnotationResolve(MockEnvironment environment, PropertiesPlaceholderResolver resolver) {
environment.setProperty("nacos.username:", "SuperZ1999");
Annotation[] annotations = TestAnnotation.class.getAnnotations();
Properties resolvedProperties = resolver.resolve(annotations[0]);
Assert.assertEquals(resolvedProperties.get("username"), "SuperZ1999");
}
@NacosProperties
@interface TestAnnotation {
}

View File

@ -0,0 +1,39 @@
/*
*
* * 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 com.alibaba.nacos.spring.util.config;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.env.MockEnvironment;
/**
* {@link NacosConfigLoader} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class NacosConfigLoaderTest {
@Test
public void testNacosConfigLoader() {
MockEnvironment environment = new MockEnvironment();
NacosConfigLoader nacosConfigLoader = new NacosConfigLoader(environment);
Integer convert = environment.getConversionService().convert("12", Integer.class);
Assert.assertEquals(Integer.valueOf(12), convert);
}
}

View File

@ -13,7 +13,7 @@
<context:property-placeholder order="0"></context:property-placeholder>
<nacos:annotation-driven read-type-from-daraId="false"/>
<nacos:annotation-driven />
<nacos:global-properties server-addr="${nacos.server-addr}"/>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>nacos-spring-parent</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.0.0</version>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -15,26 +15,25 @@
<name>Alibaba Nacos :: Samples :: Embedded Web Server</name>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>nacos-spring-samples</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.0.0</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -16,45 +16,34 @@
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-embedded-webserver</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
@ -75,7 +64,7 @@
<!-- ServletContext 路径 -->
<path>/</path>
<buildDirectory>${user.dir}/target</buildDirectory>
<finalName>${artifactId}.war</finalName>
<finalName>${project.artifactId}.war</finalName>
</configuration>
</execution>
</executions>

View File

@ -73,7 +73,7 @@ public class NacosPropertySourceConfiguration {
try {
ConfigService configService = NacosFactory.createConfigService(properties);
// Publish for FIRST_DATA_ID
publishConfig(configService, FIRST_DATA_ID, "user.name = Mercy Ma");
publishConfig(configService, FIRST_DATA_ID, "user.name = Mercy Ma\npeople.enable=false");
// Publish for BEFORE_OS_ENV_DATA_ID
publishConfig(configService, BEFORE_OS_ENV_DATA_ID, "PATH = /home/my-path");

View File

@ -20,6 +20,7 @@ import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Controller;
@ -44,6 +45,9 @@ public class ConfigServiceController {
@NacosValue(value = "${people.enable}", autoRefreshed = true)
private String enable;
@NacosValue(value = "#{'${people.list:zhangsan,lisi}'.split(',')}", autoRefreshed = true)
private List list;
@NacosInjected
private ConfigService configService;
@ -61,6 +65,12 @@ public class ConfigServiceController {
return enable;
}
@RequestMapping(value = "/list")
@ResponseBody
public Object list() {
return list;
}
@RequestMapping(value = "/publish", method = POST)
@ResponseBody
public boolean publish(@RequestParam String dataId,

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>nacos-spring-parent</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.0.0</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -20,31 +20,16 @@
<module>nacos-spring-webmvc-sample</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

127
pom.xml
View File

@ -12,14 +12,14 @@
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-parent</artifactId>
<version>1.0.0</version>
<version>${revision}</version>
<name>Alibaba Nacos :: Spring :: POM</name>
<packaging>pom</packaging>
<modules>
<module>nacos-spring-context</module>
<module>nacos-spring-samples</module>
<module>nacos-spring-context-aot</module>
</modules>
<scm>
@ -51,14 +51,12 @@
</mailingLists>
<developers>
<developer>
<id>Alibaba Nacos</id>
<name>Nacos</name>
<url>http://nacos.io</url>
<email>nacos_dev@linux.alibaba.com</email>
</developer>
<developer>
<id>mercyblitz</id>
<name>小马哥</name>
@ -76,22 +74,27 @@
</licenses>
<properties>
<revision>2.1.1</revision>
<argLine>-Dfile.encoding=UTF-8</argLine>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Compiler settings properties -->
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<!-- Exclude all generated code -->
<sonar.jacoco.itReportPath>${project.basedir}/../test/target/jacoco-it.exec
</sonar.jacoco.itReportPath>
<sonar.exclusions>file:**/generated-sources/**,**/test/**</sonar.exclusions>
<!-- Nacos -->
<nacos.version>1.3.2</nacos.version>
<nacos.version>2.2.1</nacos.version>
<!-- Spring -->
<spring.framework.version>3.2.18.RELEASE</spring.framework.version>
<!--snake-yaml-->
<snake.yaml.version>1.19</snake.yaml.version>
<spring.framework.version>5.2.9.RELEASE</spring.framework.version>
<logback-classic.version>1.2.9</logback-classic.version>
<guava.version>32.0.0-jre</guava.version>
<spring6.framework.version>6.0.8</spring6.framework.version>
<snakeyaml.version>1.29</snakeyaml.version>
<!-- Servlet -->
<servlet-api.version>3.0.1</servlet-api.version>
<!-- javax-->
@ -100,87 +103,118 @@
<commons-lang3.version>3.4</commons-lang3.version>
<!-- Alibaba's Spring Context Support -->
<spring-context-support.version>1.0.11</spring-context-support.version>
<jackson-core.version>2.13.4</jackson-core.version>
<slf4j.version>1.7.7</slf4j.version>
<junit.version>4.12</junit.version>
<mockito-core.version>2.15.0</mockito-core.version>
</properties>
<!-- 管理依赖版本号,子项目不会默认依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snake.yaml.version}</version>
</dependency>
<!-- Alibaba's Spring Context Support -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-context-support.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation-api.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
</dependency>
<!--yaml-->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework.version}</version>
<optional>true</optional>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.15.0</version>
<version>${mockito-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-classic.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-embedded-webserver</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -281,9 +315,35 @@
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
@ -296,6 +356,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<useProjectReferences>false</useProjectReferences>
<additionalConfig>
@ -317,14 +378,17 @@
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>0.0.21</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@ -334,6 +398,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
</plugin>
</plugins>
</build>