Git Product home page Git Product logo

nacos-spring-project's Introduction

Nacos Spring Project

Build Status

Nacos is an open source project for discovering, configuring and managing cloud-native applications. Key features of Nacos include:

  • Service Discovery and Service Health Check
  • Dynamic Configuration Management
  • Dynamic DNS Service
  • Service and Metadata Management

Nacos Spring Project, which is based on Nacos, fully embraces the Spring ecosystem and is designed to help you build Spring applications rapidly.

The project contains a core module named nacos-spring-context. It enables you to expand modern Java programming models in the following ways:

These features strongly depend on Spring Framework 3.2+ API, and can be seamlessly integrated with any Spring Stack, such as Spring Boot and Spring Cloud.

Note: We recommend that you use annotation-driven programming, even though XML-based features also work.

Content

1. Samples

Included in this section are some samples for you to get a quick start with Nacos Spring.

1.1. Samples

1.2. How To Run the Samples

Take the Spring Web MVC project for example:

  1. Check out the source code of nacos-spring-project :

    $ git clone [email protected]:nacos-group/nacos-spring-project.git

  2. Build your source code with Maven:

    $ mvn clean package

  3. Run Spring Web MVC Samples:

    $ java -jar target/nacos-spring-webmvc-sample.war

2. Dependencies & Compatibility

The following table shows the dependencies and compatabilities of Nacos Spring Project.

Dependencies Compatibility
Java 1.8+
Spring Context 3.2+
Alibaba Spring Context Support 1.0.1+
Alibaba Nacos 1.1.1+

3. Quickstart

This quickstart shows you how to enable Nacos and its service discovery and configuration management features in your Spring project.

3.1. Prerequisite

Before you configure your Spring project to use Nacos, you need to start a Nacos server in the backend. Refer to Nacos Quick Start for instructions on how to start a Nacos server.

3.2. Enable Nacos

Complete the following steps to enable Nacos for your Spring project.

  1. Add nacos-spring-context in your Spring application's dependencies:

        <dependencies>
            ...
            
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-spring-context</artifactId>
                <version>1.1.0</version>
            </dependency>
            
            ...
        </dependencies>

Note: Support Spring 5 from version 0.2.3-RC1, support Spring 6 from version 2.1.0.

  1. Add the @EnableNacos annotation in the @Configuration class of Spring and specify "${host}:${port}" of your Nacos server in the serverAddr attribute:

    @Configuration
    @EnableNacos(
            globalProperties =
            @NacosProperties(serverAddr = "${nacos.server-addr:localhost:12345}")
    )
    public class NacosConfiguration {
        ...
    }

3.3. Enable configuration service

Now you would like to use the confguration service of Nacos. Simply use Dependency Injection to inject ConfigService instance in your Spring Beans when @EnableNacos is annotated, as shown below:

@Service
public class ConfigServiceDemo {

    @NacosInjected
    private ConfigService configService;
    
    public void demoGetConfig() {
        try {
            String dataId = "{dataId}";
            String group = "{group}";
            String content = configService.getConfig(dataId, groupId, 5000);
        	System.out.println(content);
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }
    ...
}

ConfigService is the key interface of Nacos which helps you to get or publish configurations.

The following code achieves the same effect:

try {
    // Initialize the configuration service, and the console automatically obtains the following parameters through the sample code.
	String serverAddr = "{serverAddr}";
	String dataId = "{dataId}";
	String group = "{group}";
	Properties properties = new Properties();
	properties.put("serverAddr", serverAddr);
	ConfigService configService = NacosFactory.createConfigService(properties);
    // Actively get the configuration.
	String content = configService.getConfig(dataId, group, 5000);
	System.out.println(content);
} catch (NacosException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

3.4. Enable Service Discovery

If you would also like to use the service discovery feature of Nacos, you can inject a NamingService instance for service discovery:

    @NacosInjected
    private NamingService namingService;

For details about the usages of ConfigService and NamingService, please refer to Nacos SDK.

4. Core Features

This section provides a detailed description of the key features of nacos-spring-context:

4.1. Annotation-Driven

4.1.1. Enable Nacos

@EnableNacos is a modular-driven annotation that enables all features of Nacos Spring, including Service Discovery and Distributed Configuration. It equals to @EnableNacosDiscovery and @EnableNacosConfig, which can be configured separately and used in different scenarios.

4.1.2. Configure Change Listener method

Suppose there was a config in Nacos Server whose dataId is "testDataId" and groupId is default group("DEFAULT_GROUP"). Now you would like to change its content by using the ConfigService#publishConfig method:

    @NacosInjected
    private ConfigService configService;

    @Test
    public void testPublishConfig() throws NacosException {
        configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
    }

Then you would like to add a listener, which will be listening for the config changes. You can do this by adding a config change listener method into your Spring Beans:

    @NacosConfigListener(dataId = DATA_ID)
    public void onMessage(String config) {
        assertEquals("mercyblitz", config); // asserts true
    }

The code below has the same effect:

	configService.addListener(DATA_ID, DEFAULT_GROUP, new AbstractListener() {
        @Override
        public void receiveConfigInfo(String config) {
            assertEquals("9527", config); // asserts true
        }
    });

Note: @NacosConfigListener supports richer type conversions.

4.1.2.1. Type Conversion

The type conversion of @NacosConfigListener includes both build-in and customized implementations. By default, build-in type conversion is based on Spring DefaultFormattingConversionService, which means it covers most of the general cases as well as the rich features of the higher Spring framework.

For example, the content "9527" in the preceding example can also be listened by a method with integer or the Integer argument:

    @NacosConfigListener(dataId = DATA_ID)
    public void onInteger(Integer value) {
        assertEquals(Integer.valueOf(9527), value); // asserts true
    }

    @NacosConfigListener(dataId = DATA_ID)
    public void onInt(int value) {
        assertEquals(9527, value); // asserts true
    }

Of course, nacos-spring-context provides elastic extension for developers. If you define a named nacosConfigConversionService Spring Bean whose type is ConversionService , the DefaultFormattingConversionService will be ignored. In addition, you can customize the implementation of the NacosConfigConverter interface to specify a listener method for type conversion:

public class UserNacosConfigConverter implements NacosConfigConverter<User> {

    @Override
    public boolean canConvert(Class<User> targetType) {
        return true;
    }

    @Override
    public User convert(String source) {
        return JSON.parseObject(source, User.class);
    }
}

The UserNacosConfigConverter class binds the @NacosConfigListener.converter() attribute:

	@NacosInjected
    private ConfigService configService;

	@Test
    public void testPublishUser() throws NacosException {
        configService.publishConfig("user", DEFAULT_GROUP, "{\"id\":1,\"name\":\"mercyblitz\"}");
    }

    @NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class)
    public void onUser(User user) {
        assertEquals(Long.valueOf(1L), user.getId()); 
        assertEquals("mercyblitz", user.getName());
    }
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:

java -DyamlAllowComplexObject=true -jar your-application.jar

4.1.2.2. Timeout of Execution

As it might cost some time to run customized NacosConfigConverter, you can set max execution time in the @NacosConfigListener.timeout() attribute to prevent it from blocking other listeners:

@Configuration
public class Listeners {

    private Integer integerValue;

    private Double doubleValue;

    @NacosConfigListener(dataId = DATA_ID, timeout = 50)
    public void onInteger(Integer value) throws Exception {
        Thread.sleep(100); // timeout of execution
        this.integerValue = value;
    }

    @NacosConfigListener(dataId = DATA_ID, timeout = 200)
    public void onDouble(Double value) throws Exception {
        Thread.sleep(100); // normal execution
        this.doubleValue = value;
    }

    public Integer getIntegerValue() {
        return integerValue;
    }

    public Double getDoubleValue() {
        return doubleValue;
    }
}

The integerValue of Listeners Bean is always null and will not be changed. Therefore, those asserts will be true:

    @Autowired
    private Listeners listeners;

    @Test
    public void testPublishConfig() throws NacosException {
        configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
        assertNull(listeners.getIntegerValue()); // asserts true
        assertEquals(Double.valueOf(9527), listeners.getDoubleValue());   // asserts true
    }

4.1.3. Global and Special Nacos Properties

The globalProperties is a required attribute in any @EnableNacos, @EnableNacosDiscovery or @EnableNacosConfig, and its type is @NacosProperties. globalProperties initializes "Global Nacos Properties" that will be used by other annotations and components, e,g @NacosInjected. In other words, Global Nacos Properties" defines the global and default properties. It is set with the lowest priority and can be overridden if needed. The precedence of overiding rules is shown in the following table:

Precedence Order Nacos Annotation Required
1 *.properties() N
2 @EnableNacosConfig.globalProperties() or @EnableNacosDiscovery.globalProperties() Y
3 @EnableNacos.globalProperties() Y

*.properties() defines special Nacos properties which come from one of the following:

  • @NacosInjected.properties()
  • @NacosConfigListener.properties()
  • @NacosPropertySource.properties()
  • @NacosConfigurationProperties.properties()

Special Nacos properties are also configured by @NacosProperties. However, they are optional and are used to override Global Nacos Properties in special scenarios. If not defined, the Nacos Properties will try to retrieve properities from @EnableNacosConfig.globalProperties() or @EnableNacosDiscovery.globalProperties(), or @EnableNacos.globalProperties().

4.1.4. Nacos Properties

@NacosProperties is a uniform annotation for global and special Nacos properties. It serves as a mediator between Java Properties and NacosFactory class. NacosFactory is responsible for creating ConfigService or NamingService instances.

The attributes of @NacosProperties completely support placeholders whose source is all kinds of PropertySource in Spring Environment abstraction, typically Java System Properties and OS environment variables. The prefix of all placeholders are nacos.. The mapping between the attributes of @NacosProperties and Nacos properties are shown below:

Attribute Property Placeholder Description Required
endpoint() endpoint ${nacos.endpoint:} N
namespace() namespace ${nacos.namespace:} N
accessKey() access-key ${nacos.access-key:} N
secretKey() secret-key ${nacos.secret-key:} N
serverAddr() server-addr ${nacos.server-addr:} Y
contextPath() context-path ${nacos.context-path:} N
clusterName() cluster-name ${nacos.cluster-name:} N
encode() encode ${nacos.encode:UTF-8} N

Note that there are some differences in the placeholders of globalProperties() between @EnableNacosDiscovery and @EnableNacosConfig:

Attribute @EnableNacosDiscovery's Placeholder @EnableNacosConfig's Placeholder
endpoint() ${nacos.discovery.endpoint:${nacos.endpoint:}} ${nacos.config.endpoint:${nacos.endpoint:}}
namespace() ${nacos.discovery.namespace:${nacos.namespace:}} ${nacos.config.namespace:${nacos.namespace:}}
accessKey() ${nacos.discovery.access-key:${nacos.access-key:}} ${nacos.config.access-key:${nacos.access-key:}}
secretKey() ${nacos.discovery.secret-key:${nacos.secret-key:}} ${nacos.config.secret-key:${nacos.secret-key:}}
serverAddr() ${nacos.discovery.server-addr:${nacos.server-addr:}} ${nacos.config.server-addr:${nacos.server-addr:}}
contextPath() ${nacos.discovery.context-path:${nacos.context-path:}} ${nacos.config.context-path:${nacos.context-path:}}
clusterName() ${nacos.discovery.cluster-name:${nacos.cluster-name:}} ${nacos.config.cluster-name:${nacos.cluster-name:}}
encode() ${nacos.discovery.encode:${nacos.encode:UTF-8}} ${nacos.config.encode:${nacos.encode:UTF-8}}

These placeholders of @EnableNacosDiscovery and @EnableNacosConfig are designed to isolate different Nacos servers, and are unnecessary in most scenarios. By default, general placeholders will be reused.

4.2. Dependency Injection

@NacosInjected is a core annotation which is used to inject ConfigService or NamingService instance in your Spring Beans and make these instances cacheable. This means the instances will be the same if their @NacosProperties are equal, regargless of whether the properties come from global or special Nacos properties:

    @NacosInjected
    private ConfigService configService;

    @NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
    private ConfigService configService2;

    @NacosInjected(properties = @NacosProperties(encode = "GBK"))
    private ConfigService configService3;

    @NacosInjected
    private NamingService namingService;

    @NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
    private NamingService namingService2;

    @NacosInjected(properties = @NacosProperties(encode = "GBK"))
    private NamingService namingService3;

    @Test
    public void testInjection() {

        Assert.assertEquals(configService, configService2);
        Assert.assertNotEquals(configService2, configService3);

        Assert.assertEquals(namingService, namingService2);
        Assert.assertNotEquals(namingService2, namingService3);
    }

The property configService uses @EnableNacos#globalProperties() or @EnableNacosConfig#globalProperties(), and because the default value of the encode attribute is “UTF-8”, therefore the configService instance and the configService2 instance which is annotated by @NacosProperties(encode = "UTF-8") are the same. The same is true for namingService and namingService2.

More importantly, unlike the ConfigService instances created by the NacosFactory.createConfigService() method, the ConfigService instances created by the @NacosInjected annotation support Nacos Spring events. For instance, there will be an NacosConfigPublishedEvent after an enhanced ConfigService invokes the publishConfig() method. Refer to the Event/Listener Driven section for more details.

4.3. Externalized Configuration

Externalized configuration is a concept introduced by Spring Boot, which allows applications to receive external property sources to control runtime behavior. Nacos Server runs an isolation process outside the application to maintain the application configurations. nacos-spring-context provides properties features including object binding, dynamic configuration(auto-refreshed) and so on, and dependence on Spring Boot or Spring Cloud framework is required.

Here is a simple comparison between nacos-spring-context and Spring stack:

Spring Stack Nacos Spring Highlight
@Value @NacosValue auto-refreshed
@ConfigurationProperties @NacosConfigurationProperties auto-refreshed,@NacosProperty,@NacosIgnore
@PropertySource @NacosPropertySource auto-refreshed, precedence order control
@PropertySources @NacosPropertySources

4.4. Event/Listener Driven

Nacos Event/Listener Driven is based on the standard Spring Event/Listener mechanism. The ApplicationEvent of Spring is an abstract super class for all Nacos Spring events:

Nacos Spring Event Trigger
NacosConfigPublishedEvent After ConfigService.publishConfig()
NacosConfigReceivedEvent AfterListener.receiveConfigInfo()
NacosConfigRemovedEvent After configService.removeConfig()
NacosConfigTimeoutEvent ConfigService.getConfig() on timeout
NacosConfigListenerRegisteredEvent After ConfigService.addListner() or ConfigService.removeListener()
NacosConfigurationPropertiesBeanBoundEvent After @NacosConfigurationProperties binding
NacosConfigMetadataEvent After Nacos Config operations

5. Modules

6. Relative Projects

nacos-spring-project's People

Contributors

985492783 avatar akitata avatar brotherlu-xcq avatar chakawelkin avatar chuntaojun avatar coderdylan avatar dangzhicairang avatar ddatsh avatar dmsolr avatar horizonzy avatar hujun-w-2 avatar hxy1991 avatar jayupadhyay-8 avatar jsbxyyx avatar keran213539 avatar maijh97 avatar mercyblitz avatar oliverwqcwrw avatar onewe avatar qxo avatar realjacksun avatar rushsky518 avatar stone-98 avatar superz1999 avatar zshun avatar zxn-git avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nacos-spring-project's Issues

Catch java.lang.ClassCastException in NacosPropertySourceBeanDefinitionParser

public static void main(String[] args) {
    new ClassPathXmlApplicationContext("classpath:/test.xml");
}

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:nacos="http://nacos.io/schema/nacos"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://nacos.io/schema/nacos
        http://nacos.io/schema/nacos.xsd">

    <nacos:annotation-driven/>

    <nacos:global-properties server-addr="127.0.0.1" />

    <nacos:property-source data-id="user" auto-refreshed="true" />

</beans>

The following exception is thrown at runtime

Caused by: java.lang.ClassCastException: org.springframework.beans.factory.support.DefaultListableBeanFactory cannot be cast to org.springframework.context.ApplicationEventPublisher
	at com.alibaba.nacos.spring.context.annotation.NacosPropertySourceBeanDefinitionParser.addPropertySourceAttribute(NacosPropertySourceBeanDefinitionParser.java:94)
	at com.alibaba.nacos.spring.context.annotation.NacosPropertySourceBeanDefinitionParser.parse(NacosPropertySourceBeanDefinitionParser.java:76)
	at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1432)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1422)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:187)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:147)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:101)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:495)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391)

Add @NacosService for auto-wiring ConfigService

@NacosService Programming Model is like below :

public class ConfigServiceTest {

    @NacosService(serverAddr = "${serverAddr}")
    private ConfigService configService;

    @Test
    public void testConfigService() throws NacosException {
        String dataId = "testDataId";
        String group = "testGroupId";
        Properties properties = new Properties();
        configService.publishConfig(dataId, group, "Hello,World");
        // Actively get the configuration.
        String content = configService.getConfig(dataId, group, 5000);
        System.out.println(content);
    }
}

Some test cases will affect each other

com.alibaba.nacos.spring.config.NacosNamespaceHandlerTest
com.alibaba.nacos.spring.context.config.xml.NacosPropertySourceBeanDefinitionParserTest

By default, once loaded, the configured ApplicationContext is reused for each test. Thus the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term test suite means all tests run in the same JVM — for example, all tests run from an Ant, Maven, or Gradle build for a given project or module. In the unlikely case that a test corrupts the application context and requires reloading — for example, by modifying a bean definition or the state of an application object — the TestContext framework can be configured to reload the configuration and rebuild the application context before executing the next test.

Context management and caching

DirtiesContext

Different "Properties" are returning the same "ConfigService" instance.

import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Properties;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {CacheableEventPublishingNacosServiceFactory.class})
public class CacheableNacosServiceFactoryTest {

    @Autowired
    private NacosServiceFactory nacosServiceFactory;

    private Properties properties = new Properties();

    private Properties properties2 = new Properties();

    @Before
    public void init() {
        nacosServiceFactory = new CacheableEventPublishingNacosServiceFactory();

        properties.setProperty(PropertyKeyConst.NAMESPACE, "nc");
        properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1");
        properties.setProperty(PropertyKeyConst.ACCESS_KEY, "a");
        properties.setProperty(PropertyKeyConst.SECRET_KEY, "s");

        properties2.setProperty(PropertyKeyConst.CLUSTER_NAME, "nc");
        properties2.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1");
        properties2.setProperty(PropertyKeyConst.ACCESS_KEY, "a");
        properties2.setProperty(PropertyKeyConst.SECRET_KEY, "s");
    }

    @Test
    public void testCreateConfigService() throws NacosException {
        ConfigService configService = nacosServiceFactory.createConfigService(properties);
        ConfigService configService2 = nacosServiceFactory.createConfigService(properties2);
        // throws java.lang.AssertionError
        Assert.assertTrue(configService != configService2);
    }

    @Test
    public void testCreateNamingService() throws NacosException {
        NamingService namingService = nacosServiceFactory.createNamingService(properties);
        NamingService namingService2 = nacosServiceFactory.createNamingService(properties2);
        // throws java.lang.AssertionError
        Assert.assertTrue(namingService != namingService2);
    }
}

When using @EnableNacos and @EnableNacosConfig together, exception will be thrown

java.lang.IllegalStateException: Could not register object [java.util.concurrent.ThreadPoolExecutor@e383572[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]] under bean name 'nacosConfigListenerExecutor': there is already object [java.util.concurrent.ThreadPoolExecutor@5ddf0d24[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]] bound
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.registerSingleton(DefaultSingletonBeanRegistry.java:120) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerSingleton(DefaultListableBeanFactory.java:932) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at com.alibaba.nacos.spring.util.NacosBeanUtils.registerSingleton(NacosBeanUtils.java:115) ~[nacos-spring-context-0.1.0-SNAPSHOT.jar:na]
at com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigListenerExecutor(NacosBeanUtils.java:269) ~[nacos-spring-context-0.1.0-SNAPSHOT.jar:na]
at com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigBeans(NacosBeanUtils.java:327) ~[nacos-spring-context-0.1.0-SNAPSHOT.jar:na]
at com.alibaba.nacos.spring.context.annotation.NacosConfigBeanDefinitionRegistrar.registerBeanDefinitions(NacosConfigBeanDefinitionRegistrar.java:53) ~[nacos-spring-context-0.1.0-SNAPSHOT.jar:na]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.lambda$loadBeanDefinitionsFromRegistrars$1(ConfigurationClassBeanDefinitionReader.java:358) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:1.8.0_141]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:357) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:145) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:117) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:328) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:233) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:93) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:694) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at com.alibaba.boot.nacos.sample.ConfigApplication.main(ConfigApplication.java:65) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]

Change the style of property placeholder to be Kebab case in @NacosProperties's default value

Before

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NacosProperties {

    String endpoint() default "${nacos.endpoint:}";

    String namespace() default "${nacos.namespace:}";

    String accessKey() default "${nacos.accessKey:}";

    String secretKey() default "${nacos.secretKey:}";

    String serverAddr() default "${nacos.serverAddr:}";

    String contextPath() default "${nacos.contextPath:}";

    String clusterName() default "${nacos.clusterName:}";

    String encode() default "${nacos.encode:" + ENCODE + "}";

}

After

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NacosProperties {

    String endpoint() default "${nacos.endpoint:}";

    String namespace() default "${nacos.namespace:}";

    String accessKey() default "${nacos.access-key:}";

    String secretKey() default "${nacos.secret-key:}";

    String serverAddr() default "${nacos.server-addr:}";

    String contextPath() default "${nacos.context-path:}";

    String clusterName() default "${nacos.cluster-name:}";

    String encode() default "${nacos.encode:" + ENCODE + "}";

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.