分布式配置中心

在微服务架构中,为什么需要一个统一的配置中心呢?如果用一句话来说那就是方便管理,降低出错的可能。比如:你开发环境是一套配置,测试环境是一套,生产环境又是一套。你如果手动去修改,难免会出错吧。

Nacos

阿里开源的产品,可以作为配置中心,也可以代替Zookeeper作为服务注册中心。

正题

为了方便,我在本地建立三个不同的数据库,分别代表开发环境、测试环境、生产环境的数据库。

--

新建一个Springboot工程,修改pom文件,引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.15</druid.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>mybatis-generator</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build> <profiles>
<profile>
<id>dev</id>
<properties>
<spring.profiles>dev</spring.profiles>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>test</id>
<properties>
<spring.profiles>test</spring.profiles>
</properties>
</profile>
<profile>
<id>pro</id>
<properties>
<spring.profiles>pro</spring.profiles>
</properties>
</profile>
</profiles> </project>

先来看一下最终目录结构:

generatorConfig.xml是用来自动生成Mapper文件的,logback是用来生成日志的,config包里面是读取nocas上面的配置的,其他都是简单的东西。

-------------------------------------------

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration>
<context id="context1"> <!-- 这里引入扩展插件 -->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/> <commentGenerator>
<!-- 关闭自动生成的注释 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator> <jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mytest?useSSL=false"
userId="root"
password="1234"/>
<javaModelGenerator targetPackage="com.example.demo.model"
targetProject="src/main/java" />
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" />
<javaClientGenerator targetPackage="com.example.demo.dao"
targetProject="src/main/java" type="XMLMAPPER" /> <!--数据库的表名-->
<table tableName="user">
<generatedKey column="id" sqlStatement="MySql" identity="true" />
</table> </context>
</generatorConfiguration>

在这里双击运行即可生成需要的java类。

选择这里可以切换环境

logback-spring.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds">
<springProperty scope="context" name="LOG_HOME" source="logging.path"/> <springProfile name="dev,test,pro">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<property name="log_pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger Line:%-3L - %msg%n"/>
</springProfile> <appender name="app" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/app.log</File>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${log_pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender> <appender name="app-error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/app_error.log</File>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] [%-5level] [%logger:%L] %msg [TxId:%X{PtxId},SpanId:%X{PspanId}]%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/app_error.%d{yyyy-MM-dd}.log</FileNamePattern>
</rollingPolicy>
</appender> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<outputPatternAsHeader>true</outputPatternAsHeader>
<pattern>%black(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-6level) %black([%thread]) %boldCyan(%logger) %boldMagenta(#%method %-3L) : %black(%msg%n)</pattern>
</encoder>
</appender> <!-- 开发环境 -->
<springProfile name="dev">
<logger name="org" level="INFO"/>
<!-- level: FATAL,ERROR,WARN,INFO,DEBUG,TRACE -->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="app"/>
<appender-ref ref="app-error"/>
</root>
</springProfile> <!-- 测试&生产环境 -->
<springProfile name="test,pro">
<logger name="org" level="INFO"/>
<root level="INFO">
<appender-ref ref="app"/>
<appender-ref ref="app-error"/>
</root>
</springProfile>
</configuration>

application.yml

spring:
profiles:
active: @spring.profiles@
logging:
config: classpath:logback-spring.xml

下面打开nacos,做一下不同环境的配置

新建三个命名空间,之后进入配置管理页面,可以看到多了三个页签。

在每一个页签下添加我们需要的配置即可。(注意不同环境的数据库不一样)

url=jdbc:mysql://localhost:3306/mytest_pro?useSSL=false&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true
user_name=root
password=1234
driver_class_name=com.mysql.jdbc.Driver

不同的命名空间有不同的命名空间ID,这个有用,我们下一步会用到

属性文件的namespace填写对应的命名空间ID

application-dev.yml

server:
port: 8080
address: 0.0.0.0
nacos:
config:
server-addr: localhost:8848
namespace: 0d5b0e7c-485c-469b-9b3c-eb20dc9d9bb1
logging:
path: "./logs"

application-test.yml

server:
port: 8080
address: 0.0.0.0
nacos:
config:
server-addr: localhost:8848
namespace: b49147ed-72de-45e9-8d90-34644585a000
logging:
path: /AppLogs/boot-nacos-test

application-pro.yml

server:
port: 8080
address: 0.0.0.0
nacos:
config:
server-addr: localhost:8848
namespace: 5fb0883c-2db7-4344-9883-0394edb5c858
logging:
path: /AppLogs/boot-nacos

DatabaseConfig

package com.example.demo.config;

import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.stereotype.Component; @Component
@NacosPropertySource(dataId = "database",groupId = "DEFAULT_GROUP",autoRefreshed = true)
public class DatabaseConfig { @NacosValue(value = "${driver_class_name}", autoRefreshed = true)
private String driverClassName; @NacosValue(value = "${url}", autoRefreshed = true)
private String url; @NacosValue(value = "${user_name}", autoRefreshed = true)
private String username; @NacosValue(value = "${password}", autoRefreshed = true)
private String password; public String getDriverClassName() {
return driverClassName;
} public String getUrl() {
return url;
} public String getUsername() {
return username;
} public String getPassword() {
return password;
} }

MybatisConfiguration

package com.example.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver; import javax.sql.DataSource; @Configuration
@MapperScan(basePackages={"com.example.demo.dao"})
public class MybatisConfiguration {
@Autowired
private DatabaseConfig dataBaseConfig; @Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(dataBaseConfig.getDriverClassName());
dataSource.setUrl(dataBaseConfig.getUrl());
dataSource.setUsername(dataBaseConfig.getUsername());
dataSource.setPassword(dataBaseConfig.getPassword());
return dataSource;
} @Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml")); return sqlSessionFactoryBean.getObject();
} }

UserService

package com.example.demo.service;

import com.example.demo.model.User;

import java.util.List;

public interface UserService {

    List<User> getUserList();
}

UserServiceImpl

package com.example.demo.service.impl;

import com.example.demo.dao.UserMapper;
import com.example.demo.model.User;
import com.example.demo.model.UserExample;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.List; @Service
public class UserServiceImpl implements UserService { @Autowired
private UserMapper userMapper; @Override
public List<User> getUserList() {
UserExample example = new UserExample();
return userMapper.selectByExample(example);
}
}

UserController

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController
public class UserController { @Autowired
private UserService userService; @RequestMapping("/users")
public List<User> getUsers(){
return userService.getUserList();
}
}

其它文件由generator负责生成。下面测试,我们先本地运行。

日志在项目根目录:

下面访问:

这个是开发环境的数据。现在我们切换到测试环境,重启。

日志在当前项目磁盘的根目录

访问:数据是测试环境的数据

最后切换生产环境。日志文件:

访问:

完整地址:GitHub

nacos作为配置中心的更多相关文章

  1. Nacos系列:基于Nacos的配置中心

    前言 在看正文之前,我想请你回顾一下自己待过的公司都是怎么管理配置的,我想应该会有以下几种方式: 1.硬编码 没有什么配置不配置的,直接写在代码里面,比如使用常量类 优势:对开发友好,开发清楚地知道代 ...

  2. Nacos(四):SpringCloud项目中接入Nacos作为配置中心

    前言 通过前两篇文章: Nacos(二):Nacos与OpenFeign的对接使用 Nacos(三):SpringCloud项目中接入Nacos作为注册中心 相信大家已经对Nacos作为注册中心的基本 ...

  3. java架构之路-(微服务专题)feign的基本使用和nacos的配置中心

    上次回归: 上次我们说了ribbon的基本使用,包括里面的内部算法,算法的细粒度配置,还有我们自己如何实现我们自己的算法,主要还是一些基本使用的知识,还不会使用ribbon的小伙伴可以回去看一下上一篇 ...

  4. nacos作为配置中心动态刷新@RefreshScope添加后取值为null的一个问题

    之前springboot项目常量类如下形式: @Component @RefreshScope//nacos配置中心时添加上 public class Constants { @Value(" ...

  5. Nacos作为配置中心时,多个服务共用一个dataId的配置

    写在前面 本文是对我之前一篇文章<Spring Cloud+nacos+Feign,实现注册中心及配置中心>的补充.此文章中简单写了如何将Nacos作为配置中心.在使用配置中心时,我们会遇 ...

  6. 程序员你是如何使用Nacos作为配置中心的?

    假如你使用的是spring-cloud-alibaba微服务技术栈 单个服务独有配置文件 即去除应用程序的状态,配置统一外部化管理,方便进行水平的伸缩. 集成步骤: 假如我有一个应用app-desig ...

  7. 使用nacos作为配置中心统一管理配置

    基础环境 引入所需依赖包 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>s ...

  8. SpringBoot项目使用Nacos作为配置中心

    前置条件:jdk.SpringBoot项目.Nacos.Linux服务器(可无) 具体版本:jdk11.SpringBoot 2.3.5.RELEASE.Nacos 2.0.3.Centos 6 目标 ...

  9. Spring Cloud Alibaba基础教程:使用Nacos作为配置中心

    通过本教程的前两篇: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方 ...

随机推荐

  1. Spring笔记

    Spring概念 Spring是一个开源的轻量级的框架 Spring核心主要两部分 (1) Aop面向切面编程,扩展功能不是修改源代码实现 (2) Ioc控制反转, 比如说有一个类,在类里面有方法(不 ...

  2. 腾讯云申请SSL证书与Nginx配置Https

    0x00 为什么要安装证书 信息传输的保密性 数据交换的完整性 信息的不可否认性 交易者身份确定性 如今各大浏览器厂商不断推进Https安全访问强制性要求,为了避免以后网站数据量增多时安装证书造成不必 ...

  3. Unity 2D 效应器与来回移动的实现

    1.效应器 Point Effector 2D: 点效应器.进入区域,吸引或排斥物体 Area Effector 2D: 区域效应器,可以用来做马里奥的管道移动效果 Surface Effector ...

  4. 点击 Button触发事件将GridView1 CheckBox勾选的行添加到GridView2中

    有时候想实现一个CheckBox选取功能,但是很多细节不是很清楚 相信大家都有遇到类似的情况,直接看代码,如下: 前端代码GridView1,CheckBox控件设置 <asp:GridView ...

  5. 为什么CynosDB叫真正的云原生数据库?

    本文由腾讯云数据库发表 注:本文摘自2018年11月22日腾讯云数据库CynosDB新品发布会的演讲实录.随着互联网信息的发展,大家也对云这个词汇也不是特别陌生了,作为全球首选的云服务厂商之一的腾讯云 ...

  6. Centos7上搭建redis主从

    1. 节点(服务器)数量说明 按照redis官方建议:salve和master的数量按照2n+1台服务器(1台master节点,2n台slave节点) 有兴趣的可以了解下redis的master选举机 ...

  7. 做嵌入式,C语言相关的朋友不要错过

    前言 相对来讲嵌入式相关的人群总体来说比较少,那么有没有一个聚集地呢? 为回馈读者,「编程珠玑」与「嵌入式linux」,「EmbeddDeveloper」三个公众号联合组织了此次福利活动,「编程珠玑」 ...

  8. python接口自动化-post请求2

    一.headers 1.以禅道登录为例,模拟登陆,这里需添加请求头headers,可以用fiddler抓包 2.将请求头写成字典格式 h = { "Connection": &qu ...

  9. 利用 keras_proprecessing.image 扩增自己的遥感数据(多波段)

    1.keras 自带的 keras_proprecessing.image 只支持三种模式图片(color_mode in ['grey', 'RGB', 'RGBA'])的随机扩增. 2.遥感数据除 ...

  10. Python学习案例之Web版语音合成播报

    前言 语音合成技术能将用户输入的文字,转换成流畅自然的语音输出,并且可以支持语速.音调.音量设置,打破传统文字式人机交互的方式,让人机沟通更自然. 应用场景 将游戏场景中的公告.任务或派单信息通过语音 ...