1

foreword

The material of this article comes from the pit that a friend stepped on when integrating nacos2 as the configuration center for dynamic refresh. The problem he encountered at that time, the following screenshot

Because I was busy during that time, I found an answer that seemed to be a solution without reading the code of my friend's project and threw it away.

A friend added this configuration later, and the problem was not solved. I took a little time later and asked for his project code to look at it.

code example

Because his project is mainly a self-taught nacos project, and it does not involve any sensitive information. This article will directly take his project example to demonstrate

1. Project pom dependencies
 <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.8.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

    </dependencies>

Note: nacos server version is 2.1.1

2. The address of the nacos configuration center, which is configured in bootstrap.yml
 spring:
  cloud:
    nacos:
      server-addr: localhost:8848
3. The basic information of the project is configured in application.yml
 #
spring:
  application:
    name: nacos-config



server:
  port: 8030
4. Write a controller that needs to dynamically refresh the acquired value
 @RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {
    @Value("${user.userName:123}")
    private String userName;


    @RequestMapping("/get")
    private String get(){
        return userName;
    }




}
5. The business project is configured as follows on the nacos server

The above is a complete code example of a friend. When we run the code, we will find that the userName of the controller cannot get a value. Interested friends, you can check the above code to find out the reason

Reason for not getting value

Foreshadowing of theoretical knowledge :

When we use the cglib dynamic proxy to call the target method, when the method is decorated with private, this is the dynamic proxy object. When the method is public or protected, this is the target object. In addition, the attribute refresh brushes the attributes of the target object, and the get method of the controller can be regarded as

 @RequestMapping("/get")
    private String get(){
        return this.userName;
    }

When we add the @RefreshScope annotation to the controller, if we do not change the value of the proxyMode property, it will generate a cglib dynamic proxy by default. When we call the get method, because get is a private method, we can see it as

 @RequestMapping("/get")
    private String get(){
        return cglibProxy.userName;
    }


At this time, this is the proxy object, and at this time userName is the userName of the proxy object, and the userName of the proxy object is a null value.

Solution

Method 1. Modify the proxyMode property of @RefreshScope

Change proxyMode to ScopedProxyMode.DEFAULT or ScopedProxyMode.NO



At this time, this is the target object, so it can get the value

Method 2: Change the modifier of the target method to public or protected

Example :



At this time, this is the target object, so it can get the value

3. Method 3: Use the attribute configuration class
 @Configuration
@ConfigurationProperties(prefix = "user")
public class UserProperties {

    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

controller adjusted to

 @RestController
@RequestMapping("/config")
public class ConfigController {

    @Autowired
    private UserProperties userProperties;


    @RequestMapping("/get")
    public String get(){
        return userProperties.getUserName();
    }
    
}

At this time, the controller can achieve dynamic refresh without adding @RefreshScope. Because @ConfigurationProperties on the property class itself has the characteristics of dynamic refresh

Summarize

This article is not a pit that @RefreshScope and nacos2 stepped on. It is mainly about the knowledge of dynamic agents. The title is a bit of a headline.

When some videos talk about nacos dynamic refresh, they basically use @RerfreshScope + @value on the controller to explain. In fact, a similar effect can be achieved using @ConfigurationProperties. If it is not integrated with springcloud, introduce the starter of the nacos configuration center, and use @NacosPropertySource + @NacosValue or @NacosRefresh to achieve dynamic refresh. Interested friends can try it

Finally, my friend also stepped on some pits in the process of building nacos2. Interested friends can view the following articles

Remember the pit you stepped on using nacos2 once


linyb极客之路
336 声望193 粉丝