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();
}
相关推荐
小江的记录本几秒前
【JVM虚拟机】JVM调优:常用JVM参数、调优核心指标、OOM排查、GC日志分析、Arthas工具使用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
程序员cxuan12 分钟前
我花了两天时间,终于把 Codex 额度掉太快的问题整明白了!!
人工智能·后端·程序员
IT_陈寒13 分钟前
Vue这个动态响应坑把我整不会了
前端·人工智能·后端
金銀銅鐵13 分钟前
[Java] 用图形化界面演示 iadd, isub, iconst_<i> 指令的效果
java·后端·python
AskHarries26 分钟前
做国内还是出海
后端
J2虾虾31 分钟前
Spring AI Alibaba文档
java·人工智能·spring
YikNjy37 分钟前
break和continue
java·开发语言·算法
SomeOtherTime38 分钟前
Geojson相关(AI回答)
java·前端·python
日月云棠1 小时前
10 Integer —— 最常用的整数包装类深度解析
java·后端
大鸡腿同学1 小时前
大模型为何总 “胡说八道”?做完 RAG 知识库,我看懂了它的底层逻辑
后端