Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
ce41f4d407 | |
|
bede11a7e2 | |
|
9388aa7f65 | |
|
4b106fb992 | |
|
9b61ef68d2 | |
|
0a75c0b8c0 | |
|
eb8b10f3f3 | |
|
b209b291c2 | |
|
fcf008405b | |
|
1ada9f4e88 | |
|
b1351d7f88 | |
|
96d08e679d | |
|
5f0eb0b0d9 | |
|
0e660eb3ab | |
|
d4543ecb97 | |
|
e8cae2c501 |
|
@ -35,4 +35,5 @@ classes
|
||||||
/bin/
|
/bin/
|
||||||
*.prefs
|
*.prefs
|
||||||
*~
|
*~
|
||||||
.extract
|
.extract
|
||||||
|
.flattened-pom.xml
|
||||||
|
|
28
README.md
28
README.md
|
@ -41,6 +41,7 @@ Content
|
||||||
- [4.1.1. Enable Nacos](#411-enable-nacos)
|
- [4.1.1. Enable Nacos](#411-enable-nacos)
|
||||||
- [4.1.2. Configure Change Listener method](#412-configure-change-listener-method)
|
- [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. 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.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.3. Global and Special Nacos Properties](#413-global-and-special-nacos-properties)
|
||||||
- [4.1.4. `@NacosProperties`](#414-nacosproperties)
|
- [4.1.4. `@NacosProperties`](#414-nacosproperties)
|
||||||
|
@ -130,7 +131,7 @@ Complete the following steps to enable Nacos for your Spring project.
|
||||||
</dependencies>
|
</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:
|
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)
|
- 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)
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
|
||||||
|
com.alibaba.nacos.spring.aot.NacosAnnotationBeanRegistrationAotProcessor
|
|
@ -5,57 +5,62 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>nacos-spring-parent</artifactId>
|
<artifactId>nacos-spring-parent</artifactId>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<artifactId>nacos-spring-context</artifactId>
|
<artifactId>nacos-spring-context</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<name>Alibaba Nacos :: Spring :: Context</name>
|
<name>Alibaba Nacos :: Spring :: Context</name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<!-- java-->
|
<!-- java-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
<version>${javax.annotation-api.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Nacos -->
|
<!-- Nacos -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<artifactId>nacos-client</artifactId>
|
<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>
|
</dependency>
|
||||||
|
|
||||||
<!--yaml-->
|
<!--yaml-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>${snake.yaml.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Framework -->
|
<!-- Spring Framework -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Context Extras -->
|
<!-- Spring Context Extras -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.spring</groupId>
|
<groupId>com.alibaba.spring</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
|
@ -63,22 +68,27 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-test</artifactId>
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||||
import com.alibaba.nacos.api.config.ConfigService;
|
import com.alibaba.nacos.api.config.ConfigService;
|
||||||
import com.alibaba.nacos.api.naming.NamingService;
|
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.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
|
||||||
import com.alibaba.spring.util.BeanUtils;
|
import com.alibaba.spring.util.BeanUtils;
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
|
||||||
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(NacosBeanDefinitionRegistrar.class)
|
@Import({NacosBeanDefinitionRegistrar.class, EnableNacosAotProcessor.class})
|
||||||
public @interface EnableNacos {
|
public @interface EnableNacos {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,7 @@ import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
|
||||||
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(NacosConfigBeanDefinitionRegistrar.class)
|
@Import({NacosConfigBeanDefinitionRegistrar.class, EnableNacosConfigAotProcessor.class})
|
||||||
public @interface EnableNacosConfig {
|
public @interface EnableNacosConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
@ -48,7 +50,6 @@ import org.springframework.util.ReflectionUtils;
|
||||||
import com.alibaba.nacos.api.config.annotation.NacosValue;
|
import com.alibaba.nacos.api.config.annotation.NacosValue;
|
||||||
import com.alibaba.nacos.common.utils.MD5Utils;
|
import com.alibaba.nacos.common.utils.MD5Utils;
|
||||||
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
|
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
|
||||||
import com.alibaba.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injected {@link NacosValue}
|
* Injected {@link NacosValue}
|
||||||
|
@ -181,7 +182,7 @@ public class NacosValueAnnotationBeanPostProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object resolveNotifyValue(String nacosValueExpr, String key, String newValue) {
|
private Object resolveNotifyValue(String nacosValueExpr, String key, String newValue) {
|
||||||
String spelExpr = nacosValueExpr.replaceAll("\\$\\{" + key + PLACEHOLDER_SUFFIX, newValue);
|
String spelExpr = StringUtils.replace(nacosValueExpr, PLACEHOLDER_PREFIX + key + PLACEHOLDER_SUFFIX, newValue);
|
||||||
return resolveStringValue(spelExpr);
|
return resolveStringValue(spelExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
|
||||||
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(NacosDiscoveryBeanDefinitionRegistrar.class)
|
@Import({NacosDiscoveryBeanDefinitionRegistrar.class, EnableNacosDiscoveryAotProcessor.class})
|
||||||
public @interface EnableNacosDiscovery {
|
public @interface EnableNacosDiscovery {
|
||||||
/**
|
/**
|
||||||
* The prefix of property name of Nacos discovery
|
* The prefix of property name of Nacos discovery
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,8 +26,8 @@ import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.slf4j.Logger;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
|
@ -54,7 +54,7 @@ import org.springframework.util.ReflectionUtils;
|
||||||
public abstract class AnnotationListenerMethodProcessor<A extends Annotation>
|
public abstract class AnnotationListenerMethodProcessor<A extends Annotation>
|
||||||
implements ApplicationListener<ContextRefreshedEvent> {
|
implements ApplicationListener<ContextRefreshedEvent> {
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
private final Class<A> annotationType;
|
private final Class<A> annotationType;
|
||||||
|
|
||||||
public AnnotationListenerMethodProcessor() {
|
public AnnotationListenerMethodProcessor() {
|
||||||
|
|
|
@ -122,6 +122,23 @@ public class EventPublishingConfigService
|
||||||
return 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
|
@Override
|
||||||
public boolean removeConfig(String dataId, String group) throws NacosException {
|
public boolean removeConfig(String dataId, String group) throws NacosException {
|
||||||
boolean removed = configService.removeConfig(dataId, group);
|
boolean removed = configService.removeConfig(dataId, group);
|
||||||
|
@ -157,7 +174,7 @@ public class EventPublishingConfigService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy lifecycle method to invoke {@link #shutDown()}
|
* Destroy lifecycle method to invoke {@link #shutDown()}
|
||||||
* @throws Exception
|
* @throws Exception throw exception
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class NacosConfigurationPropertiesBinder {
|
||||||
environment);
|
environment);
|
||||||
final String type;
|
final String type;
|
||||||
|
|
||||||
ConfigType typeEunm = properties.yaml() ? ConfigType.YAML : properties.type();
|
ConfigType typeEunm = properties.type();
|
||||||
if (ConfigType.UNSET.equals(typeEunm)) {
|
if (ConfigType.UNSET.equals(typeEunm)) {
|
||||||
type = NacosUtils.readFileExtension(dataId);
|
type = NacosUtils.readFileExtension(dataId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,10 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.spring.util.aot.AotDetector;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
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.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
@ -80,15 +82,15 @@ public class NacosPropertySourcePostProcessor
|
||||||
*/
|
*/
|
||||||
public static final String BEAN_NAME = "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 ConfigurableEnvironment environment;
|
||||||
|
|
||||||
private Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
|
protected Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
|
||||||
|
|
||||||
private ConfigServiceBeanBuilder configServiceBeanBuilder;
|
protected ConfigServiceBeanBuilder configServiceBeanBuilder;
|
||||||
|
|
||||||
public static void addListenerIfAutoRefreshed(
|
public static void addListenerIfAutoRefreshed(
|
||||||
final NacosPropertySource nacosPropertySource, final Properties properties,
|
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) {
|
ConfigurableListableBeanFactory beanFactory) {
|
||||||
|
|
||||||
if (processedBeanNames.contains(beanName)) {
|
if (processedBeanNames.contains(beanName)) {
|
||||||
|
@ -179,6 +181,12 @@ public class NacosPropertySourcePostProcessor
|
||||||
|
|
||||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||||
|
|
||||||
|
doProcessPropertySource(beanName, beanDefinition);
|
||||||
|
|
||||||
|
processedBeanNames.add(beanName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doProcessPropertySource(String beanName, BeanDefinition beanDefinition) {
|
||||||
// Build multiple instance if possible
|
// Build multiple instance if possible
|
||||||
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(
|
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(
|
||||||
beanName, beanDefinition);
|
beanName, beanDefinition);
|
||||||
|
@ -190,8 +198,6 @@ public class NacosPropertySourcePostProcessor
|
||||||
.resolveProperties(nacosPropertySource.getAttributesMetadata());
|
.resolveProperties(nacosPropertySource.getAttributesMetadata());
|
||||||
addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);
|
addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
processedBeanNames.add(beanName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NacosPropertySource> buildNacosPropertySources(String beanName,
|
private List<NacosPropertySource> buildNacosPropertySources(String beanName,
|
||||||
|
|
|
@ -87,7 +87,7 @@ public enum FileTypeEnum {
|
||||||
* Get the corresponding FileTypeEnum by file extension or fileType. If not found FileTypeEnum.TEXT is returned
|
* Get the corresponding FileTypeEnum by file extension or fileType. If not found FileTypeEnum.TEXT is returned
|
||||||
*
|
*
|
||||||
* @param extOrFileType file extension or fileType
|
* @param extOrFileType file extension or fileType
|
||||||
* @return
|
* @return return {@link FileTypeEnum}
|
||||||
*/
|
*/
|
||||||
public static FileTypeEnum getFileTypeEnumByFileExtensionOrFileType(String extOrFileType) {
|
public static FileTypeEnum getFileTypeEnumByFileExtensionOrFileType(String extOrFileType) {
|
||||||
if (StringUtils.isNotBlank(extOrFileType)) {
|
if (StringUtils.isNotBlank(extOrFileType)) {
|
||||||
|
|
|
@ -86,7 +86,19 @@ class DelegatingNamingService
|
||||||
throws NacosException {
|
throws NacosException {
|
||||||
delegate.registerInstance(serviceName, groupName, instance);
|
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
|
@Override
|
||||||
public void deregisterInstance(String serviceName, String ip, int port)
|
public void deregisterInstance(String serviceName, String ip, int port)
|
||||||
throws NacosException {
|
throws NacosException {
|
||||||
|
|
|
@ -92,7 +92,8 @@ public final class ConfigParseUtils {
|
||||||
|
|
||||||
if (DEFAULT_CONFIG_PARSE_MAP.containsKey(type)) {
|
if (DEFAULT_CONFIG_PARSE_MAP.containsKey(type)) {
|
||||||
ConfigParse configParse = DEFAULT_CONFIG_PARSE_MAP.get(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 {
|
else {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.spring.context.annotation.config.SpringValueAnnotationBeanPostProcessor;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
|
@ -362,6 +363,13 @@ public abstract class NacosBeanUtils {
|
||||||
NacosValueAnnotationBeanPostProcessor.class);
|
NacosValueAnnotationBeanPostProcessor.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void registerStringValueAnnotationBeanPostProcessor(
|
||||||
|
BeanDefinitionRegistry registry) {
|
||||||
|
registerInfrastructureBeanIfAbsent(registry,
|
||||||
|
SpringValueAnnotationBeanPostProcessor.BEAN_NAME,
|
||||||
|
SpringValueAnnotationBeanPostProcessor.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register Nacos Common Beans
|
* Register Nacos Common Beans
|
||||||
*
|
*
|
||||||
|
@ -398,6 +406,8 @@ public abstract class NacosBeanUtils {
|
||||||
|
|
||||||
registerNacosValueAnnotationBeanPostProcessor(registry);
|
registerNacosValueAnnotationBeanPostProcessor(registry);
|
||||||
|
|
||||||
|
registerStringValueAnnotationBeanPostProcessor(registry);
|
||||||
|
|
||||||
registerConfigServiceBeanBuilder(registry);
|
registerConfigServiceBeanBuilder(registry);
|
||||||
|
|
||||||
registerLoggingNacosConfigMetadataEventListener(registry);
|
registerLoggingNacosConfigMetadataEventListener(registry);
|
||||||
|
|
|
@ -532,6 +532,7 @@ public abstract class NacosUtils {
|
||||||
* @param group config group
|
* @param group config group
|
||||||
* @param text config context
|
* @param text config context
|
||||||
* @param type config type
|
* @param type config type
|
||||||
|
* @return map format of result
|
||||||
*/
|
*/
|
||||||
public static Map<String, Object> toProperties(String dataId, String group,
|
public static Map<String, Object> toProperties(String dataId, String group,
|
||||||
String text, String type) {
|
String text, String type) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,15 +17,8 @@
|
||||||
|
|
||||||
package com.alibaba.nacos.spring.util.parse;
|
package com.alibaba.nacos.spring.util.parse;
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
import com.alibaba.nacos.api.config.ConfigType;
|
||||||
import java.util.Collection;
|
import com.alibaba.nacos.spring.util.AbstractConfigParse;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -33,14 +26,17 @@ import org.yaml.snakeyaml.DumperOptions;
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
import org.yaml.snakeyaml.constructor.Constructor;
|
import org.yaml.snakeyaml.constructor.Constructor;
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
import org.yaml.snakeyaml.nodes.Tag;
|
import org.yaml.snakeyaml.nodes.Tag;
|
||||||
import org.yaml.snakeyaml.parser.ParserException;
|
|
||||||
import org.yaml.snakeyaml.representer.Representer;
|
import org.yaml.snakeyaml.representer.Representer;
|
||||||
import org.yaml.snakeyaml.resolver.Resolver;
|
import org.yaml.snakeyaml.resolver.Resolver;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.config.ConfigType;
|
import java.util.Collection;
|
||||||
import com.alibaba.nacos.spring.util.AbstractConfigParse;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DefaultYamlConfigParse.
|
* DefaultYamlConfigParse.
|
||||||
|
@ -50,188 +46,151 @@ import com.alibaba.nacos.spring.util.AbstractConfigParse;
|
||||||
*/
|
*/
|
||||||
public class DefaultYamlConfigParse extends AbstractConfigParse {
|
public class DefaultYamlConfigParse extends AbstractConfigParse {
|
||||||
|
|
||||||
protected static final Logger LOGGER = LoggerFactory
|
protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultYamlConfigParse.class);
|
||||||
.getLogger(DefaultYamlConfigParse.class);
|
|
||||||
|
|
||||||
protected static Yaml createYaml() {
|
|
||||||
MapAppenderConstructor mapAppenderConstructor = new MapAppenderConstructor();
|
|
||||||
Representer representer = new Representer();
|
|
||||||
DumperOptions dumperOptions = new DumperOptions();
|
|
||||||
LimitedResolver resolver = new LimitedResolver();
|
|
||||||
LoaderOptions loaderOptions = new LoaderOptions();
|
|
||||||
loaderOptions.setAllowDuplicateKeys(false);
|
|
||||||
return new Yaml(mapAppenderConstructor, representer, dumperOptions, loaderOptions, resolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean process(MatchCallback callback, Yaml yaml, String content) {
|
private static final String YAML_ALLOW_COMPLEX_OBJECT = "yamlAllowComplexObject";
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean process(Map<String, Object> map, MatchCallback callback) {
|
private static boolean getYamlAllowComplexObject() {
|
||||||
if (LOGGER.isDebugEnabled()) {
|
return Boolean.getBoolean(YAML_ALLOW_COMPLEX_OBJECT);
|
||||||
LOGGER.debug("Merging document (no matchers set): " + map);
|
}
|
||||||
}
|
|
||||||
callback.process(getFlattenedMap(map));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
protected static Yaml createYaml() {
|
||||||
protected static Map<String, Object> asMap(Object object) {
|
LoaderOptions loaderOptions = new LoaderOptions();
|
||||||
// YAML can have numbers as keys
|
loaderOptions.setAllowDuplicateKeys(false);
|
||||||
Map<String, Object> result = new LinkedHashMap();
|
SafeConstructor constructor;
|
||||||
if (!(object instanceof Map)) {
|
if (getYamlAllowComplexObject()) {
|
||||||
// A document can be a text literal
|
constructor = new Constructor(loaderOptions);
|
||||||
result.put("document", object);
|
} else {
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
Map<Object, Object> map = (Map<Object, Object>) object;
|
protected static boolean process(MatchCallback callback, Yaml yaml, String content) {
|
||||||
for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
int count = 0;
|
||||||
Object key = entry.getKey();
|
if (LOGGER.isDebugEnabled()) {
|
||||||
Object value = entry.getValue();
|
LOGGER.debug("Loading from YAML: " + content);
|
||||||
if (value instanceof Map) {
|
}
|
||||||
value = asMap(value);
|
for (Object object : yaml.loadAll(content)) {
|
||||||
}
|
if (object != null && process(asMap(object), callback)) {
|
||||||
if (key instanceof CharSequence) {
|
count++;
|
||||||
result.put(key.toString(), value);
|
}
|
||||||
}
|
}
|
||||||
else {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
result.put("[" + key.toString() + "]", value);
|
LOGGER.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") + " from YAML resource: " + content);
|
||||||
}
|
}
|
||||||
}
|
return (count > 0);
|
||||||
return result;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static class LimitedResolver extends Resolver {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
|
|
||||||
if (tag == Tag.TIMESTAMP) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.addImplicitResolver(tag, regexp, first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Map<String, Object> getFlattenedMap(Map<String, Object> source) {
|
|
||||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
||||||
buildFlattenedMap(result, source, null);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void buildFlattenedMap(Map<String, Object> result,
|
protected static boolean process(Map<String, Object> map, MatchCallback callback) {
|
||||||
Map<String, Object> source, String path) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
for (Map.Entry<String, Object> entry : source.entrySet()) {
|
LOGGER.debug("Merging document (no matchers set): " + map);
|
||||||
String key = entry.getKey();
|
}
|
||||||
if (!StringUtils.isBlank(path)) {
|
callback.process(getFlattenedMap(map));
|
||||||
if (key.startsWith("[")) {
|
return true;
|
||||||
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() : ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@SuppressWarnings("unchecked")
|
||||||
public Map<String, Object> parse(String configText) {
|
protected static Map<String, Object> asMap(Object object) {
|
||||||
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
|
// YAML can have numbers as keys
|
||||||
process(new MatchCallback() {
|
Map<String, Object> result = new LinkedHashMap();
|
||||||
@Override
|
if (!(object instanceof Map)) {
|
||||||
public void process(Map<String, Object> map) {
|
// A document can be a text literal
|
||||||
result.set(map);
|
result.put("document", object);
|
||||||
}
|
return result;
|
||||||
}, createYaml(), configText);
|
}
|
||||||
return result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
Map<Object, Object> map = (Map<Object, Object>) object;
|
||||||
public String processType() {
|
for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
||||||
return ConfigType.YAML.getType();
|
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 interface MatchCallback {
|
private static class LimitedResolver extends Resolver {
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Put Map to Properties.
|
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
|
||||||
*
|
if (tag == Tag.TIMESTAMP) {
|
||||||
* @param map {@link Map}
|
return;
|
||||||
*/
|
}
|
||||||
void process(Map<String, Object> map);
|
super.addImplicitResolver(tag, regexp, first);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static class MapAppenderConstructor extends Constructor {
|
protected static Map<String, Object> getFlattenedMap(Map<String, Object> source) {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||||
|
buildFlattenedMap(result, source, null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MapAppenderConstructor() {
|
protected static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
|
||||||
super();
|
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() : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<Object, Object> constructMapping(MappingNode node) {
|
public Map<String, Object> parse(String configText) {
|
||||||
try {
|
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
|
||||||
return super.constructMapping(node);
|
process(new MatchCallback() {
|
||||||
}
|
@Override
|
||||||
catch (IllegalStateException ex) {
|
public void process(Map<String, Object> map) {
|
||||||
throw new ParserException("while parsing MappingNode",
|
result.set(map);
|
||||||
node.getStartMark(), ex.getMessage(), node.getEndMark());
|
}
|
||||||
}
|
}, createYaml(), configText);
|
||||||
}
|
return result.get();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<Object, Object> createDefaultMap() {
|
public String processType() {
|
||||||
final Map<Object, Object> delegate = super.createDefaultMap();
|
return ConfigType.YAML.getType();
|
||||||
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
|
protected interface MatchCallback {
|
||||||
public Set<Entry<Object, Object>> entrySet() {
|
|
||||||
return delegate.entrySet();
|
/**
|
||||||
}
|
* Put Map to Properties.
|
||||||
};
|
*
|
||||||
}
|
* @param map {@link Map}
|
||||||
}
|
*/
|
||||||
|
void process(Map<String, Object> map);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,7 +124,60 @@ public class MockConfigService implements ConfigService {
|
||||||
|
|
||||||
return true;
|
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
|
@Override
|
||||||
public boolean removeConfig(String dataId, String group) throws NacosException {
|
public boolean removeConfig(String dataId, String group) throws NacosException {
|
||||||
String key = createKey(dataId, group);
|
String key = createKey(dataId, group);
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import com.alibaba.nacos.spring.util.parse.DefaultPropertiesConfigParse;
|
import com.alibaba.nacos.spring.util.parse.DefaultPropertiesConfigParse;
|
||||||
import com.alibaba.nacos.spring.util.parse.DefaultYamlConfigParse;
|
import com.alibaba.nacos.spring.util.parse.DefaultYamlConfigParse;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liaochuntao
|
* @author liaochuntao
|
||||||
|
@ -83,6 +84,13 @@ public class ConfigParseUtilsTest {
|
||||||
System.out.println(p);
|
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
|
@Test
|
||||||
public void testYamlParser() {
|
public void testYamlParser() {
|
||||||
final String yaml = "students:\n" + " - {name: lct-1,num: 12}\n"
|
final String yaml = "students:\n" + " - {name: lct-1,num: 12}\n"
|
||||||
|
|
|
@ -20,6 +20,12 @@ import java.lang.reflect.Field;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
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 org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
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>
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(classes = NacosUtilsTest.class)
|
||||||
public class NacosUtilsTest {
|
public class NacosUtilsTest {
|
||||||
|
|
||||||
@NacosInjected
|
@NacosInjected
|
||||||
|
@ -39,6 +47,9 @@ public class NacosUtilsTest {
|
||||||
@NacosInjected(properties = @NacosProperties(serverAddr = "test"))
|
@NacosInjected(properties = @NacosProperties(serverAddr = "test"))
|
||||||
private Object object2 = new Object();
|
private Object object2 = new Object();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigurableBeanFactory beanFactory;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsDefault() {
|
public void testIsDefault() {
|
||||||
|
|
||||||
|
@ -57,4 +68,17 @@ public class NacosUtilsTest {
|
||||||
Assert.assertEquals(expectedValue, NacosUtils.isDefault(nacosProperties));
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,56 @@
|
||||||
package com.alibaba.nacos.spring.util;
|
package com.alibaba.nacos.spring.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.config.annotation.NacosIgnore;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ObjectUtilsTest {
|
public class ObjectUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_map_clean() {
|
public void test_map_clean() {
|
||||||
TestObj obj = new TestObj();
|
TestObj obj = new TestObj();
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put("key", "value");
|
map.put("key", "value");
|
||||||
obj.setMap(map);
|
obj.setMap(map);
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
list.add("element");
|
||||||
|
obj.setList(list);
|
||||||
|
|
||||||
Assert.assertNotNull(map.get("key"));
|
Assert.assertNotNull(map.get("key"));
|
||||||
Assert.assertNotNull(obj.map);
|
Assert.assertNotNull(obj.map);
|
||||||
|
Assert.assertNotNull(obj.list);
|
||||||
ObjectUtils.cleanMapOrCollectionField(obj);
|
ObjectUtils.cleanMapOrCollectionField(obj);
|
||||||
map = obj.map;
|
map = obj.map;
|
||||||
Assert.assertNull(map);
|
Assert.assertNull(map);
|
||||||
|
|
||||||
|
Assert.assertNull(obj.map);
|
||||||
|
Assert.assertNotNull(obj.list);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestObj {
|
private static class TestObj {
|
||||||
|
|
||||||
private Map<String, Object> map;
|
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() {
|
public Map<String, Object> getMap() {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMap(Map<String, Object> map) {
|
public void setMap(Map<String, Object> map) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,14 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package com.alibaba.nacos.spring.util;
|
package com.alibaba.nacos.spring.util;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.alibaba.nacos.api.annotation.NacosProperties;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link PropertiesPlaceholderResolver} Test
|
* {@link PropertiesPlaceholderResolver} Test
|
||||||
*
|
*
|
||||||
|
@ -31,26 +32,39 @@ import org.springframework.mock.env.MockEnvironment;
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
public class PropertiesPlaceholderResolverTest {
|
public class PropertiesPlaceholderResolverTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolve() {
|
public void testResolve() {
|
||||||
|
|
||||||
MockEnvironment environment = new MockEnvironment();
|
MockEnvironment environment = new MockEnvironment();
|
||||||
|
|
||||||
PropertiesPlaceholderResolver resolver = new PropertiesPlaceholderResolver(
|
PropertiesPlaceholderResolver resolver = new PropertiesPlaceholderResolver(
|
||||||
environment);
|
environment);
|
||||||
|
|
||||||
|
testMapResolve(environment, resolver);
|
||||||
|
testAnnotationResolve(environment, resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testMapResolve(MockEnvironment environment, PropertiesPlaceholderResolver resolver) {
|
||||||
Map properties = new HashMap();
|
Map properties = new HashMap();
|
||||||
properties.put("my.name", "${my.name}");
|
properties.put("my.name", "${my.name}");
|
||||||
properties.put("my.age", 18);
|
properties.put("my.age", 18);
|
||||||
|
|
||||||
environment.setProperty("my.name", "mercyblitz");
|
environment.setProperty("my.name", "mercyblitz");
|
||||||
environment.setProperty("my.age", "18");
|
environment.setProperty("my.age", "18");
|
||||||
|
|
||||||
Properties resolvedProperties = resolver.resolve(properties);
|
Properties resolvedProperties = resolver.resolve(properties);
|
||||||
|
|
||||||
Assert.assertEquals(resolvedProperties.get("my.name"), "mercyblitz");
|
Assert.assertEquals(resolvedProperties.get("my.name"), "mercyblitz");
|
||||||
Assert.assertNull(resolvedProperties.get("my.age"));
|
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 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>nacos-spring-parent</artifactId>
|
<artifactId>nacos-spring-parent</artifactId>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -15,26 +15,25 @@
|
||||||
<name>Alibaba Nacos :: Samples :: Embedded Web Server</name>
|
<name>Alibaba Nacos :: Samples :: Embedded Web Server</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<artifactId>nacos-client</artifactId>
|
<artifactId>nacos-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-core</artifactId>
|
<artifactId>spring-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>nacos-spring-samples</artifactId>
|
<artifactId>nacos-spring-samples</artifactId>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -16,45 +16,34 @@
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-core</artifactId>
|
<artifactId>spring-core</artifactId>
|
||||||
<version>4.0.5.RELEASE</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-webmvc</artifactId>
|
<artifactId>spring-webmvc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>nacos-spring-context</artifactId>
|
<artifactId>nacos-spring-context</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>nacos-embedded-webserver</artifactId>
|
<artifactId>nacos-embedded-webserver</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -82,4 +71,4 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>nacos-spring-parent</artifactId>
|
<artifactId>nacos-spring-parent</artifactId>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -20,20 +20,6 @@
|
||||||
<module>nacos-spring-webmvc-sample</module>
|
<module>nacos-spring-webmvc-sample</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-webmvc</artifactId>
|
|
||||||
<version>${spring.framework.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -46,6 +32,4 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
</project>
|
||||||
|
|
||||||
</project>
|
|
||||||
|
|
124
pom.xml
124
pom.xml
|
@ -12,16 +12,16 @@
|
||||||
|
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<artifactId>nacos-spring-parent</artifactId>
|
<artifactId>nacos-spring-parent</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>${revision}</version>
|
||||||
<name>Alibaba Nacos :: Spring :: POM</name>
|
<name>Alibaba Nacos :: Spring :: POM</name>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>nacos-spring-context</module>
|
<module>nacos-spring-context</module>
|
||||||
<module>nacos-spring-samples</module>
|
<module>nacos-spring-samples</module>
|
||||||
|
<module>nacos-spring-context-aot</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<url>git@github.com:nacos-group/nacos-spring-project.git</url>
|
<url>git@github.com:nacos-group/nacos-spring-project.git</url>
|
||||||
<connection>scm:git@github.com:nacos-group/nacos-spring-project.git</connection>
|
<connection>scm:git@github.com:nacos-group/nacos-spring-project.git</connection>
|
||||||
|
@ -51,14 +51,12 @@
|
||||||
</mailingLists>
|
</mailingLists>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
|
|
||||||
<developer>
|
<developer>
|
||||||
<id>Alibaba Nacos</id>
|
<id>Alibaba Nacos</id>
|
||||||
<name>Nacos</name>
|
<name>Nacos</name>
|
||||||
<url>http://nacos.io</url>
|
<url>http://nacos.io</url>
|
||||||
<email>nacos_dev@linux.alibaba.com</email>
|
<email>nacos_dev@linux.alibaba.com</email>
|
||||||
</developer>
|
</developer>
|
||||||
|
|
||||||
<developer>
|
<developer>
|
||||||
<id>mercyblitz</id>
|
<id>mercyblitz</id>
|
||||||
<name>小马哥</name>
|
<name>小马哥</name>
|
||||||
|
@ -76,12 +74,13 @@
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<revision>2.1.1</revision>
|
||||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<!-- Compiler settings properties -->
|
<!-- Compiler settings properties -->
|
||||||
<maven.compiler.source>1.6</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.6</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
|
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
|
||||||
<!-- Exclude all generated code -->
|
<!-- Exclude all generated code -->
|
||||||
|
@ -89,11 +88,13 @@
|
||||||
</sonar.jacoco.itReportPath>
|
</sonar.jacoco.itReportPath>
|
||||||
<sonar.exclusions>file:**/generated-sources/**,**/test/**</sonar.exclusions>
|
<sonar.exclusions>file:**/generated-sources/**,**/test/**</sonar.exclusions>
|
||||||
<!-- Nacos -->
|
<!-- Nacos -->
|
||||||
<nacos.version>1.4.1</nacos.version>
|
<nacos.version>2.2.1</nacos.version>
|
||||||
<!-- Spring -->
|
<!-- Spring -->
|
||||||
<spring.framework.version>3.2.18.RELEASE</spring.framework.version>
|
<spring.framework.version>5.2.9.RELEASE</spring.framework.version>
|
||||||
<!--snake-yaml-->
|
<logback-classic.version>1.2.9</logback-classic.version>
|
||||||
<snake.yaml.version>1.19</snake.yaml.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 -->
|
||||||
<servlet-api.version>3.0.1</servlet-api.version>
|
<servlet-api.version>3.0.1</servlet-api.version>
|
||||||
<!-- javax-->
|
<!-- javax-->
|
||||||
|
@ -102,87 +103,118 @@
|
||||||
<commons-lang3.version>3.4</commons-lang3.version>
|
<commons-lang3.version>3.4</commons-lang3.version>
|
||||||
<!-- Alibaba's Spring Context Support -->
|
<!-- Alibaba's Spring Context Support -->
|
||||||
<spring-context-support.version>1.0.11</spring-context-support.version>
|
<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>
|
</properties>
|
||||||
|
|
||||||
<!-- 管理依赖版本号,子项目不会默认依赖 -->
|
<!-- 管理依赖版本号,子项目不会默认依赖 -->
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
<version>${servlet-api.version}</version>
|
<version>${servlet-api.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.nacos</groupId>
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
<artifactId>nacos-client</artifactId>
|
<artifactId>nacos-client</artifactId>
|
||||||
<version>${nacos.version}</version>
|
<version>${nacos.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.yaml</groupId>
|
|
||||||
<artifactId>snakeyaml</artifactId>
|
|
||||||
<version>${snake.yaml.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Alibaba's Spring Context Support -->
|
<!-- Alibaba's Spring Context Support -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.spring</groupId>
|
<groupId>com.alibaba.spring</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
<version>${spring-context-support.version}</version>
|
<version>${spring-context-support.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>javax.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
<version>${javax.annotation-api.version}</version>
|
<version>${javax.annotation-api.version}</version>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>${commons-lang3.version}</version>
|
<version>${commons-lang3.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Framework -->
|
<!-- Spring Framework -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-core</artifactId>
|
<artifactId>spring-core</artifactId>
|
||||||
<version>${spring.framework.version}</version>
|
<version>${spring.framework.version}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
<version>${spring.framework.version}</version>
|
<version>${spring.framework.version}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.12</version>
|
<version>${junit.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-test</artifactId>
|
<artifactId>spring-test</artifactId>
|
||||||
<version>${spring.framework.version}</version>
|
<version>${spring.framework.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>2.15.0</version>
|
<version>${mockito-core.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
@ -283,6 +315,31 @@
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<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>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
@ -341,6 +398,11 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>3.4.0</version>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue