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+"\tid: "+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]+"\t 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); } }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM