SpringBoot整合Nacos

文章目录

nacos

nacos下载

下载地址

一键傻瓜试安装即可,官网写的很清楚这里不在赘述 http://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html

nacos启动

将模式改为单机模式

启动成功

nacos相关配置

demo-dev.yaml
yaml 复制代码
server:
  port: 8001

config:
  info: "config info for dev from nacos config center"
demo-test.yaml
yaml 复制代码
server:
  port: 3333

config:
  info: "config info for test from nacos config center"
user.yaml
yaml 复制代码
user:
  name: zs1112222
  age: 10
  address: 测试地址

代码

整合nacos配置中心,注册中心,完整项目地址 gitee地址

pom.xml

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
</dependencies>

UserConfig

java 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "user")
public class UserConfig {

    private String name;

    private Integer age;

    private String address;

}

BeanAutoRefreshConfigExample

java 复制代码
@RestController
public class BeanAutoRefreshConfigExample {

    @Autowired
    private UserConfig userConfig;

    @GetMapping("/user/hello")
    public String hello(){
        return userConfig.getName() + userConfig.getAge() + userConfig.getAddress();
    }

}

ValueAnnotationExample

java 复制代码
@RestController
@RefreshScope
public class ValueAnnotationExample {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
        return configInfo;
    }

}

DemoApplication

java 复制代码
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

bootstrap.yml

yaml 复制代码
spring:
  profiles:
    # 指定环境 切换环境
    active: dev
  application:
    name: demo
  cloud:
    # nacos server dataId
    # ${spring.application.name)}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
    nacos:
      # Nacos服务注册中心
      discovery:
        serverAddr: @serverAddr@
        group: DEMO_GROUP
        namespace: 25af15f3-ae79-41c3-847d-960adb953185
        username: @username@
        password: @password@
      # Nacos作为配置中心
      config:
        server-addr: @serverAddr@
        file-extension: yaml
        group: DEMO_GROUP
        namespace: 25af15f3-ae79-41c3-847d-960adb953185
        username: @username@
        password: @password@
        # 加载多配置
        extension-configs:
          - data-id: user.yaml
            group: DEMO_GROUP
            refresh: true

测试结果

补充.刷新静态配置

有时候一些老项目或者一些写法会遇到静态的配置,这时候可以利用Java的反射特性来刷新静态变量.

大致原理为: 监听nacos配置改动,通过nacos改动确定改动的配置,进而缩小更新范围,通过反射更新变量.

xml 复制代码
<!-- https://mvnrepository.com/artifact/com.purgeteam/dynamic-config-spring-boot-starter -->
<dependency>
    <groupId>com.purgeteam</groupId>
    <artifactId>dynamic-config-spring-boot-starter</artifactId>
    <version>0.1.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

@NacosRefreshStaticField

java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NacosRefreshStaticField {

    String configPrefix() default "";

}

NacosListener

java 复制代码
@Slf4j
@Component
@EnableDynamicConfigEvent
public class NacosListener implements ApplicationListener<ActionConfigEvent> {

    @Autowired
    private ApplicationContext applicationContext;

    @SneakyThrows
    @Override
    public void onApplicationEvent(ActionConfigEvent environment) {
        Map<String, HashMap> map = environment.getPropertyMap();
        for (Map.Entry<String, HashMap> entry : map.entrySet()) {
            String key = entry.getKey();
            Map changeMap = entry.getValue();
            String before = String.valueOf(changeMap.get("before"));
            String after = String.valueOf(changeMap.get("after"));
            log.info("配置[key:{}]被改变,改变前before:{},改变后after:{}",key,before,after);

            String[] configNameArr = key.split("\\.");
            String configPrefix = configNameArr[0];
            String configRealVal = configNameArr[configNameArr.length-1];

            AtomicReference<Class<?>> curClazz = new AtomicReference<>();
            Map<String, Object> refreshStaticFieldBeanMap = applicationContext.getBeansWithAnnotation(NacosRefreshStaticField.class);
            for (Map.Entry<String, Object> mapEntry : refreshStaticFieldBeanMap.entrySet()) {
                String beanName = mapEntry.getKey();
                if (ObjectUtil.isEmpty(beanName)) {
                    continue;
                }

                String fullClassName = refreshStaticFieldBeanMap.get(beanName).toString().split("@")[0];
                Class<?> refreshStaticFieldClass;
                try {
                    refreshStaticFieldClass = Class.forName(fullClassName);
                } catch (ClassNotFoundException e) {
                    throw new ClassNotFoundException("监听nacos刷新当前静态类属性,未找到当前类",e);
                }
                NacosRefreshStaticField refreshStaticConfig = refreshStaticFieldClass.getAnnotation(NacosRefreshStaticField.class);
                if (Objects.nonNull(refreshStaticConfig) && refreshStaticConfig.configPrefix().equalsIgnoreCase(configPrefix)) {
                    curClazz.set(refreshStaticFieldClass);
                }
            }
            Class<?> aClass = curClazz.get();
            if (Objects.isNull(aClass)) {
                return;
            }

            // 利用反射动态更新 静态变量
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if (declaredField.getName().equalsIgnoreCase(configRealVal)) {
                    log.info("刷新当前配置 更新当前类[{}] 静态属性 [{}]",aClass.getSimpleName(),declaredField.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(null,after);
                }
            }

        }

    }
}

CommonWebConfig

java 复制代码
@Data
@Component
@ConfigurationProperties(prefix = "common")
@RefreshScope
public class CommonWebConfig {

    private String apiUrl;

}

使用

java 复制代码
@Component
@NacosRefreshStaticField(configPrefix="common")
public class ExampleComponent {
    public static String apiUrl = SpringUtil.getBean(CommonWebConfig.class).getApiUrl();
}
相关推荐
苏三说技术18 分钟前
为什么越来越多人用Arthas 4 ?
后端
Thomas.Sir20 分钟前
第13课:MyBatis-Plus整合SpringBoot4.x,分页、条件查询、逻辑删除实战
java·spring boot
ServBay28 分钟前
AI 开发平台出事后,API Key 泄露要怎么办
后端·aigc·ai编程
程序员老申36 分钟前
解剖 PDF 底层二进制:一行代码如何抓出假薪资流水的 3 处破绽
后端
meiying88381 小时前
多快递公司快递单号批量查询接口怎么对接?Python 聚合查询实现
java·大数据·python
古法安卓1 小时前
Android-GPU压测工具
android·java·android studio
JuiceFS1 小时前
从 Meta 的工程实践看 EB 级 AI 存储架构
人工智能·后端
数据库小学妹1 小时前
MySQL NULL陷阱:NOT IN、三值逻辑与NOT EXISTS
数据库·后端·mysql
AI入职记1 小时前
10 万个会话吃掉 1.1G 内存:Spring AI 会话记忆的两个隐藏成本
后端
小兔子1 小时前
getenv 返回的是别人的内存,改一下会改变整个进程的环境
后端