分布式配置中心
在微服务架构中,为什么需要一个统一的配置中心呢?如果用一句话来说那就是方便管理,降低出错的可能。比如:你开发环境是一套配置,测试环境是一套,生产环境又是一套。你如果手动去修改,难免会出错吧。
Nacos
阿里开源的产品,可以作为配置中心,也可以代替Zookeeper作为服务注册中心。
正题
为了方便,我在本地建立三个不同的数据库,分别代表开发环境、测试环境、生产环境的数据库。
--
新建一个Springboot工程,修改pom文件,引入相关依赖
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 5.1.47 1.1.15 org.springframework.boot spring-boot-starter-web com.alibaba.boot nacos-config-spring-boot-starter 0.2.1 org.mybatis.spring.boot mybatis-spring-boot-starter 2.0.0 mysql mysql-connector-java ${mysql.version} com.alibaba druid ${druid.version} org.springframework.boot spring-boot-devtools runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin org.apache.maven.plugins maven-compiler-plugin 3.7.0 org.mybatis.generator mybatis-generator-maven-plugin 1.3.7 true true mybatis-generator generate mysql mysql-connector-java ${mysql.version} dev dev true test test pro pro
先来看一下最终目录结构:
generatorConfig.xml是用来自动生成Mapper文件的,logback是用来生成日志的,config包里面是读取nocas上面的配置的,其他都是简单的东西。
-------------------------------------------
generatorConfig.xml
在这里双击运行即可生成需要的java类。
选择这里可以切换环境
logback-spring.xml
${LOG_HOME}/app.log ${log_pattern} INFO ${LOG_HOME}/app.%d{yyyy-MM-dd}.log 30 ${LOG_HOME}/app_error.log %d{yyyy-MM-dd HH:mm:ss} [%thread] [%-5level] [%logger:%L] %msg [TxId:%X{PtxId},SpanId:%X{PspanId}]%n ERROR ${LOG_HOME}/app_error.%d{yyyy-MM-dd}.log true %black(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-6level) %black([%thread]) %boldCyan(%logger) %boldMagenta(#%method %-3L) : %black(%msg%n)
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=trueuser_name=rootpassword=1234driver_class_name=com.mysql.jdbc.Driver
不同的命名空间有不同的命名空间ID,这个有用,我们下一步会用到
属性文件的namespace填写对应的命名空间ID
application-dev.yml
server: port: 8080 address: 0.0.0.0nacos: config: server-addr: localhost:8848 namespace: 0d5b0e7c-485c-469b-9b3c-eb20dc9d9bb1logging: path: "./logs"
application-test.yml
server: port: 8080 address: 0.0.0.0nacos: config: server-addr: localhost:8848 namespace: b49147ed-72de-45e9-8d90-34644585a000logging: path: /AppLogs/boot-nacos-test
application-pro.yml
server: port: 8080 address: 0.0.0.0nacos: config: server-addr: localhost:8848 namespace: 5fb0883c-2db7-4344-9883-0394edb5c858logging: 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 { ListgetUserList();}
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;@Servicepublic class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public ListgetUserList() { 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;@RestControllerpublic class UserController { @Autowired private UserService userService; @RequestMapping("/users") public ListgetUsers(){ return userService.getUserList(); }}
其它文件由generator负责生成。下面测试,我们先本地运行。
日志在项目根目录:
下面访问:
这个是开发环境的数据。现在我们切换到测试环境,重启。
日志在当前项目磁盘的根目录
访问:数据是测试环境的数据
最后切换生产环境。日志文件:
访问:
完整地址: