天天看點

聊聊使用@RefreshScope與nacos2整合踩到的坑

作者:linyb極客之路

前言

本文的素材來源于朋友整合nacos2作為配置中心進行動态重新整理時,踩到的坑。他當時遇到的問題,如下截圖

聊聊使用@RefreshScope與nacos2整合踩到的坑

因為那段時間比較忙,于是我在沒看朋友項目代碼的基礎上,就找個了看似解決方案的答案,扔了過去

聊聊使用@RefreshScope與nacos2整合踩到的坑

後面朋友加了這個配置,問題果然沒有解決。後面就抽了一點時間,要了他的項目代碼來看下。

代碼示例

因為他這個項目主要是他自學nacos的項目,也沒涉及啥敏感資訊。本文就直接拿他的項目示例示範

1、項目pom依賴
<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>
           

注: nacos服務端版本為2.1.1

2、nacos配置中心位址,配置在bootstrap.yml裡面
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
           
3、項目的基本資訊配置在application.yml裡面
#
spring:
  application:
    name: nacos-config



server:
  port: 8030

           
4、編寫一個需要動态重新整理擷取值的controller
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {
    @Value("${user.userName:123}")
    private String userName;


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




}

           
5、業務項目在nacos服務端上配置如下
聊聊使用@RefreshScope與nacos2整合踩到的坑

以上就是朋友完整的代碼例子。我們運作一下代碼,會發現controller的userName取不到值。感興趣的朋友,可以走查一下上述的代碼,查找一下原因

取不到值的原因

理論知識鋪墊:

當我們使用cglib動态代理調用目标方法時,當方法被private修飾時,this為動态代理對象。當方法被public或者protected修飾時,this為目标對象。此外屬性重新整理刷的是目标對象的屬性,controller的get方法可以看成是

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

           

當我們在controller加上@RefreshScope注解時,如果不改變變proxyMode這個屬性值時,他預設就會生成一個cglib動态代理。當我們調用get方法,因為get為私有方法,我們可以看成

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

           
聊聊使用@RefreshScope與nacos2整合踩到的坑

此時的this是代理對象,而此時userName是代理對象的userName,代理對象的userName是空值。

解決方法

方法一、修改@RefreshScope的proxyMode屬性

将proxyMode改為ScopedProxyMode.DEFAULT或者ScopedProxyMode.NO

聊聊使用@RefreshScope與nacos2整合踩到的坑
聊聊使用@RefreshScope與nacos2整合踩到的坑

此時this為目标對象,是以能取到值

方法二:将目标方法的修飾符改為public或者protected

示例:

聊聊使用@RefreshScope與nacos2整合踩到的坑
聊聊使用@RefreshScope與nacos2整合踩到的坑

此時this為目标對象,是以能取到值

3、方法三:使用屬性配置類
@Configuration
@ConfigurationProperties(prefix = "user")
public class UserProperties {

    private String userName;

    public String getUserName() {
        return userName;
    }

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

           

controller調整成

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

    @Autowired
    private UserProperties userProperties;


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

此時controller不用加@RefreshScope也能實作動态重新整理。因為屬性類上的@ConfigurationProperties本身就具有動态重新整理的特性

總結

本文不算是@RefreshScope與nacos2整合踩到的坑,主要還是動态代理方面的知識,題目有點标題黨了。

有些視訊講nacos動态重新整理時,基本上都是舉controller上@RerfreshScope +@value來講解。其實利用@ConfigurationProperties也是可以達到類似的效果。如果沒和springcloud整合,引入nacos配置中心的starter,使用@NacosPropertySource + @NacosValue或者@NacosRefresh也是可以實作動态重新整理,感興趣的朋友可以試一下

最後,朋友之前在nacos2搭建過程中,也踩到了一些坑。感興趣的朋友可以檢視如下文章

記一次使用nacos2踩到的坑

繼續閱讀