Nacos服务注册和配置中心
1、官方文档
nacos官网文档介绍:官方文档介绍
2、快速入门
Nacos Server安装
- 环境准备
Nacos是依赖java环境来运行的 - docker拉取镜像并创建Nacos容器
// 拉取镜像
$ docker pull nacos/nacos-server:1.4.0
// 创建容器 指定启动方式--env MODE=standalone(单机模式)、端口映射
$ docker run --name nacos --env MODE=standalone -d -p 8848:8848 nacos/nacos-server
//查看容器信息
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
828b242c0680 nacos/nacos-server:1.4.0 "bin/docker-startup.…" 23 hours ago Up 6 hours 0.0.0.0:8848->8848/tcp nacos
76fdef861ec8 mysql:latest "docker-entrypoint.s…" 2 days ago Up 6 hours 33060/tcp, 0.0.0.0:3307->3306/tcp mysql
//进入nacos容器交互界面 可以修改配置文件
$ docker exec -it 828b242c0680 /bin/bash
访问http://localhost:8848/nacos,测试是否启动成功。默认用户名及密码:nacos nacos
配置数据库
- 创建数据库
create database nacos;
执行sql文件,sql源文件地址
- 修改Nacos配置
# 进入nacos
docker exec -it nacos bash
# 修改配置文件
vim conf/application.properties
# 重启nacos
docker restart nacos
修改结果如下:
# spring
server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
server.contextPath=/nacos
server.port=${NACOS_APPLICATION_PORT:8848}
spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:""}
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
db.num=${MYSQL_DATABASE_NUM:1}
db.url.0=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true}
db.url.1=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true}
db.user=${MYSQL_SERVICE_USER}
db.password=${MYSQL_SERVICE_PASSWORD}
### The auth system to use, currently only 'nacos' is supported:
nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}
### The token expiration in seconds:
nacos.core.auth.default.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:
注意:连接的数据库用户需要host为%
集成配置中心
添加依赖
目前推荐使用版本为:官方版本说明
<?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>
<!-- 项目坐标地址 -->
<groupId>com.demo</groupId>
<!-- 项目模块名称 -->
<artifactId>nacos</artifactId>
<!-- 项目版本名称 快照版本SNAPSHOT、正式版本RELEASE -->
<version>0.0.1-SNAPSHOT</version>
<!--
集中定义依赖组件版本号,但不引入,
在子工程中用到声明的依赖时,可以不加依赖的版本号,
这样可以统一管理工程中用到的依赖版本
-->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- spring-boot-starter-parent 依赖 -->
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<!-- Spring Cloud Hoxton.SR9 依赖 -->
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<!-- spring cloud alibaba 依赖 -->
<alibaba-cloud.version>2.2.6.RELEASE</alibaba-cloud.version>
</properties>
<!-- 项目依赖管理 父项目只是声明依赖,子项目需要写明需要的依赖(可以省略版本信息) -->
<dependencyManagement>
<dependencies>
<!-- spring boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${alibaba-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
配置中心测试数据库连接
- 创建配置 在命名空间中创建对应空间,不创建默认使用public,为了做好dev prop test等环境区分用
在配置列表中创建配置
Nacos Config 使用 Data ID
和 Group
来确定配置。
下图显示 Data Id
为 springboot-nacos-demo
,组使用默认组,并添加 yaml
格式的配置信息。
spring:
#阿里巴巴druid数据源配置
datasource:
type: com.alibaba.druid.pool.DruidDataSource
sql-script-encoding: utf-8
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
username: erp_dev
url: jdbc:mysql://172.28.188.103:3306/erp_finance?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai
password: localf%BiAiSYyWhS#PN8
filter:
config:
enabled: true
# 连接池的配置信息
# 初始化时建立物理连接的个数
initial-size: 3
# 连接池最小连接数
min-idle: 3
# 连接池最大连接数
max-active: 20
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
# 既作为检测的间隔时间又作为testWhileIdel执行的依据
time-between-connect-error-millis: 60000
# 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
min-evictable-idle-time-millis: 30000
# 用来检测连接是否有效的sql 必须是一个查询语句
# mysql中为 select 'x'
# oracle中为 select 1 from dual
validationQuery: select 'x'
# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-borrow: false
# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-return: false
# 是否缓存preparedStatement,mysql5.5+建议开启
pool-prepared-statements: true
# 当值大于0时poolPreparedStatements会自动修改为true
max-pool-prepared-statement-per-connection-size: 20
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: false
# 配置扩展插件
#监控统计拦截的filters
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 定时输出统计信息到日志中,并每次输出日志会导致清零(reset)连接池相关的计数器。
time-between-log-stats-millis: 300000
# 配置DruidStatFilter
web-stat-filter:
enabled: true
url-pattern: '/*'
exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*'
# 配置DruidStatViewServlet
stat-view-servlet:
# 是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
enabled: true
url-pattern: '/druid/*'
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.0.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.0.128
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: admin
- 创建项目 在父工程下创建子项目【nacos_config_test】
- 添加依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos_config_test</artifactId>
<parent>
<artifactId>nacos</artifactId>
<groupId>com.demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos-config 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
- 配置文件
在
bootstrap.yml
中配置 Nacos Server 的地址和应用名
spring:
cloud:
nacos:
config:
group: DEFAULT_GROUP # 组,默认为 DEFAULT_GROUP
server-addr: 127.0.0.1:8848 # Nacos Server 地址
enabled: true # 如果不想使用 Nacos 进行配置管理,设置为 false 即可
file-extension: yml # 配置的文件类型 默认为properties
prefix: springboot-nacos-demo # 前缀 不配置默认取spring.application.name
namespace: 1407edc1-461a-4ee1-86b8-386065dbaf69 #命名空间
在 Nacos Spring Cloud 中,dataId
的完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}
prefix
默认为spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置。
spring.profile.active
即为当前环境对应的 profile。注意:当spring.profile.active
为空时,对应的连接符-
也将不存在,dataId 的拼接格式将变成${prefix}.${file-extension}
-
file-exetension
为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension
来配置。目前只支持properties
和yaml
类型,默认为properties
。 -
自定义DruidDatasouceWrapper
DruidDatasouceWrapper
要继承DruidDataSource
RefreshScope
的作用是实现配置、实例热加载,也就是我们重写修改配置信息后,spring
会销毁当前类的实例,然后重新创建一个新的实例放到容器中,也是实现数据源配置实时更新的关键
package com.demo.nacos_config_test.wrapper;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName DruidDataSourceWrapper
* @Description TODO
* @Author hanhang
* @Date 2021/7/17 10:23 上午
**/
@Configuration
@RefreshScope
public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
@Value("${spring.datasource.druid.url}")
private String url;
@Value("${spring.datasource.druid.username}")
private String username;
@Value("${spring.datasource.druid.password}")
private String password;
@Value("${spring.datasource.druid.driver-class-name}")
private String driverClassName;
private String passwordCallbackClassName;
public void setMaxWait(int maxWait) {
this.maxWait = maxWait;
}
@Override
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
@Override
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
@Override
public void setUrl(String url) {
this.url = url;
}
@Override
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
@Override
public void setPasswordCallbackClassName(String passwordCallbackClassName) {
this.passwordCallbackClassName = passwordCallbackClassName;
}
@Override
public void afterPropertiesSet() throws Exception {
// 如果未找到前缀“spring.datasource.druid”JDBC属性,将使用“Spring.DataSource”前缀JDBC属性。
super.setUrl(url);
super.setUsername(username);
super.setPassword(password);
super.setDriverClassName(driverClassName);
super.setInitialSize(initialSize);
super.setMinIdle(minIdle);
super.setMaxActive(maxActive);
super.setMaxWait(maxWait);
super.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
super.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
super.setValidationQuery(validationQuery);
super.setTestWhileIdle(testWhileIdle);
super.setTestOnBorrow(testOnBorrow);
super.setTestOnReturn(testOnReturn);
super.setPoolPreparedStatements(poolPreparedStatements);
super.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
super.setDbType(dbType);
super.setPasswordCallbackClassName(passwordCallbackClassName);
}
}
- 配置Nacos
这里关键的配置就一个,
EnableAutoConfiguration
启动springboot
的自动自动配置,下面的方法是在初始化的时候,创建数据源实例,同样也启用了热加载
package com.demo.nacos_config_test.conf;
import com.alibaba.druid.pool.DruidDataSource;
import com.demo.nacos_config_test.wrapper.DruidDataSourceWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName NacosConfigConfiguration
* @Description TODO
* @Author hanhang
* @Date 2021/7/17 10:28 上午
**/
@Slf4j
@EnableAutoConfiguration
@Configuration
public class NacosConfigConfiguration {
@Bean(initMethod = "init")
@ConditionalOnMissingBean
@RefreshScope
public DruidDataSource dataSource(){
log.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
- 测试
如下日志信息,我们可以看到
springboot
启动的时候加载了nacos
发布的配置信息,然后还会有数据源初始成功的提示信息:
然后我们写一个controller
测试下:
package com.demo.nacos_config_test.controller;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.demo.nacos_config_test.wrapper.DruidDataSourceWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName NacosConfigController
* @Description TODO
* @Author hanhang
* @Date 2021/7/15 4:00 下午
**/
@RestController
@RequestMapping("/nacos")
@RequiredArgsConstructor
public class NacosConfigController {
private final DruidDataSourceWrapper dataSourceWrapper;
@GetMapping("/get")
@ResponseBody
public List<String> get() throws SQLException {
DruidPooledConnection connection = dataSourceWrapper.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * from base_other_platform_payment;");
List<String> sup = new ArrayList<>();
while(resultSet.next()){
if (!sup.contains(resultSet.getString("supplier_name"))){
sup.add(resultSet.getString("supplier_name"));
}
}
return sup;
}
}
有两个数据库,都有base_other_platform_payment
表,我现在的数据库地址配的是172.28.188.103:3306/erp_financese
这个库,请求结果如下:
切换至127.0.0.1:3306/erp_financese
这个库,请求结果如下:
测试配置中心热部署数据库完成。
服务注册与发现
使用两个maven项目来测试注册中心的功能,一个项目提供服务叫nacos-discovery-test
项目,另一个项目则转发该服务并具有断路器功能,叫nacos-consumer-test
,将两个项目注册到Nacos注册中心。
服务提供者
- 创建项目
在父工程下创建子项目【nacos_discovery_test】
- 添加依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos_discovery_test</artifactId>
<parent>
<artifactId>nacos</artifactId>
<groupId>com.demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
- 配置文件
# 应用名称
spring:
application:
name: nacos-discovery-test
cloud:
nacos:
discovery:
enabled: true
server-addr: 127.0.0.1:8848
namespace: 948d40f9-6dfb-45de-b62d-c8035423d2e8
server:
port: 8762
- 更多配置
主类上进行注解@EnableDiscoveryClient
开启Spring Cloud的服务注册与发现
package com.demo.nacos_discovery_test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author hanhang
*/
@EnableDiscoveryClient
@SpringBootApplication
public class NacosDiscoveryTestApplication {
public static void main(String[] args) {
SpringApplication.run(NacosDiscoveryTestApplication.class, args);
}
}
创建测试接口
package com.demo.nacos_discovery_test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName HelloController
* @Description TODO
* @Author hanhang
* @Date 2021/7/19 9:48 上午
**/
@RestController
public class HelloController {
@GetMapping(value = "/hello")
public String hello() {
return "Hello , I am provider";
}
}
观察日志,发现下图所示,即添加成功
- 测试
调用http://localhost:8762/hello返回结果
服务消费者
- 创建项目
在父工程下创建子项目【nacos_consumer_test】
- 添加依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos_consumer_test</artifactId>
<parent>
<artifactId>nacos</artifactId>
<groupId>com.demo</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
- 配置文件
# 应用名称
spring:
application:
name: nacos-consumer-test
cloud:
nacos:
discovery:
enabled: true
server-addr: 127.0.0.1:8848
namespace: 948d40f9-6dfb-45de-b62d-c8035423d2e8
server:
port: 8763
feign:
hystrix:
enabled: true #开启熔断
- 更多配置
主类上进行注解@EnableDiscoveryClient
开启Spring Cloud的服务注册与发现,添加
@EnableFeignClients
开启Feign
package com.demo.nacos_consumer_test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class NacosConsumerTestApplication {
public static void main(String[] args) {
SpringApplication.run(NacosConsumerTestApplication.class, args);
}
}
Remote接口程序实现转发和转发失败时的回调功能
package com.demo.nacos_consumer_test.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 注:feign不识别【_】识别【-】
* @author hanhang
*/
@FeignClient(name = "nacos-discovery-test",fallback = RemoteHystrix.class)
public interface RemoteClient {
@GetMapping("/hello")
String helloNacos();
}
RemoteHystrix程序实现Remote接口,定义回调方法
package com.demo.nacos_consumer_test.client;
import org.springframework.stereotype.Component;
/**
* @ClassName RemoteHystrix
* @Description TODO
* @Author hanhang
* @Date 2021/7/19 10:12 上午
**/
@Component
public class RemoteHystrix implements RemoteClient {
@Override
public String helloNacos() {
return "请求超时了";
}
}
创建测试接口
package com.demo.nacos_consumer_test.controller;
import com.demo.nacos_consumer_test.client.RemoteClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName FeignTestController
* @Description TODO
* @Author hanhang
* @Date 2021/7/19 10:16 上午
**/
@RestController
public class FeignTestController {
@Autowired
private RemoteClient remoteClient;
@GetMapping("/feign")
public String getTest(){
return remoteClient.helloNacos();
}
}
观察日志,发现下图所示,即添加成功
- 测试