zoukankan      html  css  js  c++  java
  • nacos作为配置中心兼容xml配置文件

      最近公司想要用配置中心,因为公司用的有传统的spring项目,有springboot项目,为了兼容都能够采用配置中心,做了一些尝试,经过比较还是倾向于使用nacos,传统dubbo采用spring方式读取xml读取配置文件的方式启动,其配置数据源,redis,rabbitmq等采用的是xml的配置,xml中取值是个问题,为了兼容xml能从远程配置中心更好的取值,做了一系列尝试。

      比较当前的一些配置中心

     Nacos的部署结构比较简单,运维成本较低。Apollo部署组件较多,运维成本比Nacos高。Spring Cloud Config生产高可用的成本最高。

    Apollo支持Spring Boot和Spring Cloud项目,但是实现方式不同于标准,无法做无缝迁移,从Spring Cloud迁移到Apollo,存在代码改造和兼容性成本。
    Nacos通过Spring Cloud for Alibaba支持Spring Boot和Spring Cloud生态,符合Spring生态中的标准实现方式,可以无缝从Spring Cloud Conig迁移到Nacos。
    Apollo和Nacos相对于Spring Cloud Config的生态支持更广,在配置管理流程上做的更好。
    Apollo相对于Nacos在配置管理做的更加全面,但使用起来也要麻烦一些。
    Nacos使用起来相对比较简洁,在对性能要求比较高的大规模场景更适合。 此外,Nacos除了提供配置中心的功能,还提供了动态服务发现、服务共享与管理的功能,降低了服务化改造过程中的难度。 Nacos目前项目上的人力投入、社区的活跃度等也比较高
    整体上来看,Nacos的读写性能最高,Apollo次之,Spring Cloud Config的依赖Git场景不适合开放的大规模自动化运维API

     一、传统的spring加载xml项目启动兼容

    典型启动方式是:

    1 public static void main(String[] args) throws IOException {
    2         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
    3                 new String[] {"applicationContext.xml"});
    4         context.start();
    5         System.out.println("------------");
    6         System.in.read(); // 为保证服务一直开着, 利用输入流的阻塞来模拟.
    7     }

    这种项目不适合通过注解进行,所以只能采用配置,网上参考的有些坑,主要是jar包冲突的问题,这里放上我修改的jar依赖

    <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-spring-context</artifactId>
                <version>0.3.0</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

    application-nacos.xml

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:nacos="http://nacos.io/schema/nacos"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xsi:schemaLocation="http://nacos.io/schema/nacos http://nacos.io/schema/nacos.xsd
     5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     6 
     7 
     8     <!--nacos配置,这里是使用配置文件的方式,这只是其中的一种方式-->
     9     <!--开启注解-->
    10     <nacos:annotation-driven></nacos:annotation-driven>
    11     <!--指定nacos配置地址-->
    12     <nacos:global-properties server-addr="localhost:8848"/>
    13     <!--指定dataId,group-id, 是否是自动刷新-->
    14     <nacos:property-source data-id="dubbo-config" group-id="DEFAULT_GROUP" auto-refreshed="true"/>
    15 </beans>

    同时需要将该xml导入到基本的application.xml中

    <import resource="spring/applicationContext-nacos.xml" />

    nacos配置中心上添加的配置内容需要什么配置什么即可。

    采用注解形式

    <?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://nacos.io/schema/nacos http://nacos.io/schema/nacos.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--开启注解-->
        <nacos:annotation-driven></nacos:annotation-driven>
        
    </beans>
    @Configuration
    @EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
    @NacosPropertySource(dataId = "dubbo-config", autoRefreshed = true)
    public class nacosConfig {
    
    }

    3、或者在application.xml里面整合好nacos的xml内容(命名空间,开启注解)采用注解

    xmlns:nacos="http://nacos.io/schema/nacos"
    xsi:schemaLocation="http://nacos.io/schema/nacos http://nacos.io/schema/nacos.xsd
    同时需要注意
    <nacos:annotation-driven></nacos:annotation-driven>放置的前后位置,不合适会报错,多更换几个位置试试就可以了,xml的加载顺序是从上到下来加载的

    二、springboot项目兼容xml,这里有三种方式,可以采用上面的方式,也可以采用官方文档的注解方式,但是发现采用上面的方式配置动态刷新没有成功,而采用注解方式,需要注意的是注入值应该采用@NacosValue(value ="${xxxx}",autoRefreshed = true)方能能够实现自动刷新,而采用@Value("${xxxx}")不能实现自动刷新

    第一种,采用同上面的方式

    第二种,采用注解方式,jar包采用传统spring整合的jar包,依赖同上,

    package com.topband.beings.config;
    
    import com.alibaba.nacos.api.annotation.NacosProperties;
    import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
    import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ImportResource;
    
    @Configuration
    //@ImportResource({ "classpath:config/applicationContext-nacos.xml" })注:这个是采用xml配置需要添加的,因为不是采用显示加载application.xml启动
    @EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
    @NacosPropertySource(dataId = "being-springboot-config", autoRefreshed = true)
    public class NacosConfig {
    
    }

    然后在controller注入值时采用是注入值应该采用@NacosValue(value ="${xxxx}",autoRefreshed = true)即可实现实时刷新,并且访问数据库什么的都是正常的

    第三种,采用如下jar包,然后完全按照官方文档来即可

     <dependency>
                <groupId>com.alibaba.boot</groupId>
                <artifactId>nacos-config-spring-boot-starter</artifactId>
                <version>0.2.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

    application.properties

    nacos.config.server-addr=127.0.0.1:8848

    启动类上加注解

    @SpringBootApplication
    @NacosPropertySource(dataId = "xxxx你nacos上的dataId", autoRefreshed = true)
    public class NacosConfigApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(NacosConfigApplication.class, args);
        }
    }

    同样的,采用@NacosValue(value ="${xxxx}",autoRefreshed = true)方能能够实现自动刷新,而采用@Value("${xxxx}")不能实现自动刷新,并且@NacosValue(value ="${xxxx}")也不能实时刷新,autoRefreshed默认为false

    三、springboot直接采用springcloud的jar配置

          <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <version>0.2.1.RELEASE</version>
            </dependency>

    采用上述jar包去兼容xml的取值时,报不能加载属性值错误。没有成功,后来发现是application-name写错了,修改过来后,直接可用兼容。

    四、一个springboot集成springcloud jar无xml配置的demo

      直接采用完全注解的方式加载,写了一个小demo,采用三中依赖,不用排除上面exclusions中的包,一个独立的demo,集成redis集群,运行ok

    1、bootstrap.properties

    server.port=8002
    spring.application.name=xxx-test
    spring.profiles.active=local
    spring.cloud.nacos.config.file-extension=properties
    spring.cloud.nacos.config.server-addr=127.0.0.1:8848
    #spring.cloud.nacos.config.namespace=d6775f80-ed7a-409a-8dbc-49b2cddee4d1

    在 Nacos Spring Cloud 中,dataId 的完整格式如下:

    ${prefix}-${spring.profile.active}.${file-extension}
    
    • prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
    • spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
    • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。

    通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新:

    @RestController
    @RefreshScope
    public class TestController {
        private Logger logger = LoggerFactory.getLogger(this.getClass());
        @Autowired
        RedisTemplate<String,String> template;
        @Value("${id}")
        private String id;
        @GetMapping("/getId")
        public String getId(){
            logger.info("看一看id的变化: {}",id);
            template.opsForValue().set("hello","world");
            String result = template.opsForValue().get("hello");
            return "redis result: "+result+"	id: "+id;
        }
    }

    Redis属性及配置

     1 package com.xx.test.config;
     2 
     3 
     4 import org.springframework.beans.factory.annotation.Value;
     5 import org.springframework.cloud.context.config.annotation.RefreshScope;
     6 import org.springframework.stereotype.Component;
     7 
     8 @Component
     9 @RefreshScope
    10 public class RedisProperties {
    11     @Value("${redis.expireSeconds}")
    12     private int expireSeconds;
    13     @Value("${redis.clusterNodes}")
    14     private String clusterNodes;
    15     @Value("${redis.commandTimeout}")
    16     private int commandTimeout;
    17     @Value("${redis.maxTotal}")
    18     private int maxTotal;
    19     @Value("${redis.maxTotal}")
    20     private int maxIdle;
    21     @Value("${redis.maxWaitMillis}")
    22     private int maxWaitMillis;
    23     @Value("${redis.testOnBorrow}")
    24     private boolean testOnBorrow;
    25     @Value("${redis.maxRedirects}")
    26     private int maxRedirects;
    27 
    28     public int getExpireSeconds() {
    29         return expireSeconds;
    30     }
    31 
    32     public void setExpireSeconds(int expireSeconds) {
    33         this.expireSeconds = expireSeconds;
    34     }
    35 
    36     public String getClusterNodes() {
    37         return clusterNodes;
    38     }
    39 
    40     public void setClusterNodes(String clusterNodes) {
    41         this.clusterNodes = clusterNodes;
    42     }
    43 
    44     public int getCommandTimeout() {
    45         return commandTimeout;
    46     }
    47 
    48     public void setCommandTimeout(int commandTimeout) {
    49         this.commandTimeout = commandTimeout;
    50     }
    51 
    52     public int getMaxTotal() {
    53         return maxTotal;
    54     }
    55 
    56     public void setMaxTotal(int maxTotal) {
    57         this.maxTotal = maxTotal;
    58     }
    59 
    60     public int getMaxIdle() {
    61         return maxIdle;
    62     }
    63 
    64     public void setMaxIdle(int maxIdle) {
    65         this.maxIdle = maxIdle;
    66     }
    67 
    68     public int getMaxWaitMillis() {
    69         return maxWaitMillis;
    70     }
    71 
    72     public void setMaxWaitMillis(int maxWaitMillis) {
    73         this.maxWaitMillis = maxWaitMillis;
    74     }
    75 
    76     public boolean isTestOnBorrow() {
    77         return testOnBorrow;
    78     }
    79 
    80     public void setTestOnBorrow(boolean testOnBorrow) {
    81         this.testOnBorrow = testOnBorrow;
    82     }
    83 
    84     public int getMaxRedirects() {
    85         return maxRedirects;
    86     }
    87 
    88     public void setMaxRedirects(int maxRedirects) {
    89         this.maxRedirects = maxRedirects;
    90     }
    91 }

    config

     1 package com.xxx.test.config;
     2 
     3 import com.xxx.test.common.redis.JRedisClient;
     4 import org.springframework.beans.factory.annotation.Autowired;
     5 import org.springframework.context.annotation.Bean;
     6 import org.springframework.context.annotation.Configuration;
     7 import org.springframework.data.redis.connection.RedisClusterConfiguration;
     8 import org.springframework.data.redis.connection.RedisNode;
     9 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    10 import org.springframework.data.redis.core.RedisTemplate;
    11 import org.springframework.data.redis.serializer.StringRedisSerializer;
    12 import redis.clients.jedis.JedisPoolConfig;
    13 
    14 import java.util.ArrayList;
    15 import java.util.List;
    16 
    17 @Configuration
    18 public class RedisConfig {
    19 
    20     @Autowired
    21     private RedisProperties redisProperties;
    22 
    23     @Bean
    24     public RedisClusterConfiguration redisClusterConfiguration(){
    25         RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
    26         redisClusterConfiguration.setMaxRedirects(redisProperties.getMaxRedirects());
    27 
    28         List<RedisNode> nodeList = new ArrayList<>();
    29 
    30         String[] cNodes = redisProperties.getClusterNodes().split(",");
    31         //分割出集群节点
    32         for(String node : cNodes) {
    33             String[] hp = node.split(":");
    34             System.out.println("addr: "+hp[0]+"	 ip:"+Integer.parseInt(hp[1]));
    35             nodeList.add(new RedisNode(hp[0], Integer.parseInt(hp[1])));
    36         }
    37         redisClusterConfiguration.setClusterNodes(nodeList);
    38         return redisClusterConfiguration;
    39     }
    40 
    41 
    42     @Bean
    43     public JedisPoolConfig jedisPoolConfig(){
    44         JedisPoolConfig jedisPoolConfig =  new JedisPoolConfig();
    45         jedisPoolConfig.setMaxIdle(redisProperties.getMaxIdle());
    46         jedisPoolConfig.setTestOnBorrow(redisProperties.isTestOnBorrow());
    47         jedisPoolConfig.setMaxTotal(redisProperties.getMaxTotal());
    48         jedisPoolConfig.setMaxWaitMillis(redisProperties.getMaxWaitMillis());
    49         return jedisPoolConfig;
    50     }
    51     @Bean
    52     public JedisConnectionFactory getConnectionFactory(){
    53         return new JedisConnectionFactory(redisClusterConfiguration(),jedisPoolConfig());
    54     }
    55     @Bean
    56     public StringRedisSerializer stringRedisSerializer(){
    57         return new StringRedisSerializer();
    58     }
    59     @Bean
    60     public RedisTemplate redisTemplate(){
    61         RedisTemplate redisTemplate = new RedisTemplate();
    62         redisTemplate.setConnectionFactory(getConnectionFactory());
    63         redisTemplate.setKeySerializer(stringRedisSerializer());
    64         redisTemplate.setHashKeySerializer(stringRedisSerializer());
    65         return redisTemplate;
    66     }
    67     @Bean
    68     public JRedisClient jRedisClient(){
    69         JRedisClient jRedisClient = new JRedisClient();
    70         jRedisClient.setRedisTemplate(redisTemplate());
    71         return jRedisClient;
    72     }
    73 
    74     @Bean
    75     public RedisTemplate redisTemplate2(){
    76         RedisTemplate redisTemplate = new RedisTemplate();
    77         redisTemplate.setConnectionFactory(getConnectionFactory());
    78         redisTemplate.setKeySerializer(stringRedisSerializer());
    79         redisTemplate.setHashKeySerializer(stringRedisSerializer());
    80         redisTemplate.setValueSerializer(stringRedisSerializer());
    81         return redisTemplate;
    82     }
    83     @Bean
    84     public JRedisClient jRedisClient2(){
    85         JRedisClient jRedisClient = new JRedisClient();
    86         jRedisClient.setRedisTemplate(redisTemplate2());
    87         return jRedisClient;
    88     }
    89 
    90 }

    nacos上配置按照约定的dataid进行配置即可。

    参考:官方文档https://nacos.io/zh-cn/docs/quick-start.html

    https://blog.csdn.net/qq_25484147/article/details/86358209

    @SpringBootApplication @NacosPropertySource(dataId = "example", autoRefreshed = true) public class NacosConfigApplication { public static void main(String[] args) { SpringApplication.run(NacosConfigApplication.class, args); } }

  • 相关阅读:
    136. 只出现一次的数字
    Eclipse Git Pull报 cannot open git-upload-pack错误的解决方案
    数据结构和算法1 稀疏数组
    Netty学习二 TCP粘包拆包以及Netty解决TCP粘包拆包
    Java值传递和引用传递
    Git命令教程
    Properties文件载入工具类
    有序的properties的工具类
    对象操作工具类
    反射工具类
  • 原文地址:https://www.cnblogs.com/xiaoyao-001/p/11510337.html
Copyright © 2011-2022 走看看