Skip to content

Spring Cloud 谷粒商城学习记录(1)

谷粒商城是一个B2C模式的电商平台,销售自营商品给客户,例如京东、苏宁易购、天猫、小米商城等。

系统架构图

项目技术&特色

项目前置要求

分布式基础概念

微服务

简而言之:拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行。

集群&分布式&节点

远程调用

负载均衡

服务注册/发现&注册中心

配置中心

服务熔断&服务降级

API网关

docker配置项目环境

docker安装mysql

注意:其中-d表示是以后台方式启动,mysql:5.7

docker启动mysql服务,并配置映射端口

docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=1234 \
-d mysql:5.7

-v /mydata/mysql/log:/var/log/mysql 表示将容器中的/var/log/mysql目录映射为宿主机的/mydata/mysql/log目录,我们只需要修改/mydata/mysql/log中的内容就可以同步修改容器中的内容,-e MYSQL_ROOT_PASSWORD=1234表示设置容器的环境变量MYSQL_ROOT_PASSWORD1234

-p 3306:3306 第一个端口表示宿主机的端口,这里表示将宿主机的3306端口映射为docker容器的3306端口

docker exec -it mysql mysql -uroot -p // 通过容器的 mysql 命令行工具连
docker update mysql --restart=always // 设置开机自动运行mysql容器,目的是防止虚拟器重启以后mysql服务未启动

接下来封装docker快捷启动mysql的脚本命令

/usr/local/docker/mysql/start.sh

bash
#!/bin/bash

docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=1234 \
-d mysql:5.7

docker update mysql --restart=always

/usr/local/docker/mysql/remove.sh

bash
#!/bin/bash

CONTAINER_NAME="mysql"

CONTAINER_ID=$(docker ps -aqf "name=^$CONTAINER_NAME\$")   # 获取指定容器的ID
if [ ! -z "$CONTAINER_ID" ]; then
    docker stop $CONTAINER_ID && docker rm $CONTAINER_ID   # 先停止再移除容器
fi

docker安装redis

docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

其中-d redis redis-server /etc/redis/redis.conf表示每次redis启动都会以/etc/redis/redis.conf这个配置文件来启动,而/etc/redis/redis.conf容器内的配置文件我们已经映射到宿主机外,所以我们只需要修改宿主机外配置文件即可

注意:现在redis并没有做持久化,所以在重启redis容器后数据会丢失

开启redis持久化

// /mydata/redis/conf
appendonly yes

完整的配置文件,redis.conf的标准文件在redis官网也可以找到 /mydata/redis/conf

# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
#bind 127.0.0.1

protected-mode no

port 6379

tcp-backlog 511

requirepass 000415

timeout 0

tcp-keepalive 300

daemonize no

supervised no

pidfile /var/run/redis_6379.pid

loglevel notice

logfile ""

databases 30

always-show-logo yes

save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename dump.rdb

dir ./

replica-serve-stale-data yes

replica-read-only yes

repl-diskless-sync no

repl-disable-tcp-nodelay no

replica-priority 100

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

appendonly yes

appendfilename "appendonly.aof"

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

aof-use-rdb-preamble yes

lua-time-limit 5000

slowlog-max-len 128

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

list-max-ziplist-size -2

list-compress-depth 0

set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

stream-node-max-bytes 4096
stream-node-max-entries 100

activerehashing yes

hz 10

dynamic-hz yes

aof-rewrite-incremental-fsync yes

rdb-save-incremental-fsync yes
docker exec -it redis redis-cli // 执行redis-cli连接
docker update redis --restart=always // 设置开机自动运行redis容器,目的是防止虚拟器重启以后redis服务未启动

接下来添加docker启动redis的快捷脚本

/usr/local/docker/redis/start.sh

bash
#!/bin/bash

docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

# 开机自启
docker update redis --restart=always

/usr/local/docker/redis/remove.sh

sh
#!/bin/bash

CONTAINER_NAME="redis"

CONTAINER_ID=$(docker ps -aqf "name=^$CONTAINER_NAME\$")   # 获取指定容器的ID
if [ ! -z "$CONTAINER_ID" ]; then
    docker stop $CONTAINER_ID && docker rm $CONTAINER_ID   # 先停止再移除容器
fi

docker常见命令

docker pull image // 拉取镜像文件

docker images // 缓查看当前已安装的镜像文件

sudo systemctl start docker // 启动docker

sudo systemctl enable docker  // 设置docker开机自启

docker exec -it <CONTAINER-NAME> or <CONTAINER-ID> /bin/bash // 进入容器

docker start <CONTAINER-NAME> or <CONTAINER-ID> // 启动容器

docker restart <CONTAINER-NAME> or <CONTAINER-ID> // 重启容器

docker logs <CONTAINER-NAME> or <CONTAINER-ID> // 查看容器日志

docker ps -a // 查看容器运行状态

docker inspect <CONTAINER-NAME> or <CONTAINER-ID> // 查看容器的环境变量

初始化项目结构

我们需要创建5个服务,分别是:商品服务、仓储服务、订单服务、优惠券服务、用户服务

ideaclone项目

每个微服务间有一些共同点:

1、都需要导入两个必要的微服务依赖:Spring Webopenfeign

2、每一个服务,包名固定 com.atguigu.gulimall.xxx(product/order/ware/coupon/member)

3、模块名: gulimall-coupon

创建子模块

创建第一个微服务模块

由于我们的项目是微服务项目,导入必要的包

点击next

商品服务

订单服务

仓储服务

会员服务

系统检测到多个微服务,提示开启spring-boot多服务管理面板

开启后可以在这里一键启动微服务项目

聚合项目

接下来我们需要将谷粒商城作为,我们随意在一个项目中复制一个pom.xml文件,然后粘贴到谷粒商城根目录

gulimall\pom.xml

xml
<?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>

    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>

    <modules>
        <module>gulimall-product</module>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-ware</module>
    </modules>

</project>

设置modules将其他子模块聚合起来

添加完成后发现gulimall已经变成root了,接下来直接在gulimall运行mvn命令其他子模块就会同步更新

修改gitignore文件

修改gitignore文件,去除不需要提交的文件

打开Version Control面板,点击左侧刷新按钮

将剩下的21个文件右键选择add to VCS

接下来就可以进行commit

取消勾选代码分析和检查

然后确认框点击push即可

创建数据库

每一个微服务都对应一个自己的数据库

商品服务数据库

优惠服务数据库

订单服务数据库

用户服务数据库

仓储服务数据库

复制每个数据库内容粘贴到navicat运行

创建后台管理系统

接下来我们直接使用人人开源的renren-fast和配套的reren-fast-vue来搭建后台管理系统

renren-fastrenren-fast-vue导入到谷粒商城中

renren-fast声明成一个modulepom.xml

xml
<?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>

    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>

    <modules>
        <module>gulimall-product</module>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-ware</module>
        <module>renren-fast</module>
    </modules>

</project>

创建后台管理系统数据库

复制renren-fast中的db/mysql.sql

创建后台管理系统的数据库

QRTZ开头的是定时任务的表,以sys开头的是系统常用的表

修改renre-fast开发配置

修改本地开发环境数据库地址,账号和密码 renren-fast/src/main/resources/application-dev.yml

修改结束后我们可以启动项目测试下

如果项目启动类中出现红色报错

点击配置项目结构

后台服务成功运行在8080端口

逆向工程生成业务代码

我们使用人人开源的代码生成器来生成业务代码

克隆项目,将其复制到谷粒商城中,并配置主pom.xml文件

pom.xml

xml
<?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>

    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>

    <modules>
        <module>gulimall-product</module>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-ware</module>
        <module>renren-fast</module>
        <module>renren-generator</module>
    </modules>

</project>

修改业务代码生成配置

修改代码生成服务的application.yml文件,修改数据库地址,可以先生成gulimall_pms数据库业务代码

renren-generator/src/main/resources/application.yml

yml
server:
  port: 80

# mysql
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #MySQL配置
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://101.43.17.174:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    #oracle配置
    #    driverClassName: oracle.jdbc.OracleDriver
    #    url: jdbc:oracle:thin:@47.100.206.162:1521:xe
    #    username: renren
    #    password: 123456
    #SQLServer配置
    #    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
    #    url: jdbc:sqlserver://192.168.10.10:1433;DatabaseName=renren_fast
    #    username: sa
    #    password: 123456
    #PostgreSQL配置
  #    driverClassName: org.postgresql.Driver
  #    url: jdbc:postgresql://192.168.10.10:5432/renren_fast
  #    username: postgres
  #    password: 123456



  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  resources:
    static-locations: classpath:/static/,classpath:/views/

#mongodb:
#  host: localhost
#  port: 27017
#  auth: false #是否使用密码验证
#  username: tincery
#  password: renren
#  source: 123456
#  database: test

mybatis-plus:
  mapperLocations: classpath:mapper/**/*.xml


pagehelper:
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql


#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql、mongodb】
renren:
  database: mysql

修改generator.properties配置文件

我们主要配置以下内容

renren-generator/src/main/resources/generator.properties

properties
#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F

mainPath=com.atguigu
#\u5305\u540D
package=com.atguigu.gulimall
moduleName=product
#\u4F5C\u8005
author=zhaochao
#Email
email=1798231822@qq.com
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
tablePrefix=pms_

#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F
tinyint=Integer
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean

char=String
varchar=String
tinytext=String
text=String
mediumtext=String
longtext=String


date=Date
datetime=Date
timestamp=Date

NUMBER=Integer
INT=Integer
INTEGER=Integer
BINARY_INTEGER=Integer
LONG=String
FLOAT=Float
BINARY_FLOAT=Float
DOUBLE=Double
BINARY_DOUBLE=Double
DECIMAL=BigDecimal
CHAR=String
VARCHAR=String
VARCHAR2=String
NVARCHAR=String
NVARCHAR2=String
CLOB=String
BLOB=String
DATE=Date
DATETIME=Date
TIMESTAMP=Date
TIMESTAMP(6)=Date

int8=Long
int4=Integer
int2=Integer
numeric=BigDecimal

nvarchar=String

我们启动renren-generator服务

我们勾选gulimall_pms的所有表,为其生成代码,勾选后点击生成代码

生成后的文件如下

我们复制main文件夹到gulimall/gulimall-product/src

导入项目后发现许多需要用到的工具类函数,包括mybatis plus的包都还没有引入,接下来我们进行引入

创建gulimall-common模块

我们创建一个mavn项目gulimall-common引入每一个微服务项目都需要依赖的公共依赖

gulimall-common用来保存每一个微服务公共的类和依赖,每一个微服务都依赖gulimall-common

修改gulimall-commonpom文件,添加注释 gulimall-common/pom.xml

xml
<?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">
    <parent>
        <artifactId>gulimall</artifactId>
        <groupId>com.atguigu.gulimall</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gulimall-common</artifactId>
    <description>每一个微服务公共的依赖,bean,工具类等</description>

</project>

接着配置gulimall-productpom依赖公共的gulimall-commom

gulimall-product/pom.xml

xml
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-product</name>
    <description>谷粒商城-商品服务</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.2</spring-cloud.version>
    </properties>
    <dependencies>
        <!-- 让其依赖gulimall-common包 -->
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

项目中用到了mybatis-plus插件,先引入mybatis-plus插件

gulimall-common/pom.xml

xml
 <dependency>
    <!--     mybatis-plus       -->
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.2.0</version>
</dependency>

引入刷新后gulimall-product,发现dao层已经不再报错

entity层中发现使用到了lombok依赖,我们需要引入

gulimall-common/pom.xml

xml
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>

引入后刷新maven仓库后报错就消失了

Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setterequalshashcodetoString方法。

然后我们发现还有一一些通用的工具类没有引入

我们在gulimall-common中新建包com.atguigu.common.utils,然后复制renren-fastcommon/utils下的PageUtilsRQuery工具类

其中R模块还有依赖其他包

其中org.apache.http.HttpStatus是属于org.apache.httpcomponents依赖中的一个模块 gulimall-common/pom.xml

xml
<dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
        <version>4.4.12</version>
</dependency>

Query中还需要引入依赖

其中StringUtils类引入如下依赖 gulimall-common/pom.xml

xml
 <dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

其中SQLFilterrenren-fast中的common/xss文件夹中

引入依赖

接下来引入Constant常量

我们从renren-fast``common中引入Constant工具类,如果还有依赖没引入参考renren-fast

目前仅仅是controller中的接口权限报错,这是因为用到了shiro,本项目不采用这个方案,所以可以在renren-genarator逆向工程生成代码时调整不生成RequiresPermissions

看了renren-genarator项目的pom文件后发现,其生成代码的核心插件是springframework,所以我们可以直接调整controller对应的template,我们调整模板,先将shiro注释,后面用spring-secerity来做权限控制

renren-generator/src/main/resources/template/Controller.java.vm

package ${package}.${moduleName}.controller;

import java.util.Arrays;
import java.util.Map;

##import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import ${package}.${moduleName}.entity.${className}Entity;
import ${package}.${moduleName}.service.${className}Service;
import ${mainPath}.common.utils.PageUtils;
import ${mainPath}.common.utils.R;



/**
 * ${comments}
 *
 * @author ${author}
 * @email ${email}
 * @date ${datetime}
 */
@RestController
@RequestMapping("${moduleName}/${pathName}")
public class ${className}Controller {
    @Autowired
    private ${className}Service ${classname}Service;

    /**
     * 列表
     */
    @RequestMapping("/list")
##    @RequiresPermissions("${moduleName}:${pathName}:list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = ${classname}Service.queryPage(params);

        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{${pk.attrname}}")
##    @RequiresPermissions("${moduleName}:${pathName}:info")
    public R info(@PathVariable("${pk.attrname}") ${pk.attrType} ${pk.attrname}){
		${className}Entity ${classname} = ${classname}Service.getById(${pk.attrname});

        return R.ok().put("${classname}", ${classname});
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
##    @RequiresPermissions("${moduleName}:${pathName}:save")
    public R save(@RequestBody ${className}Entity ${classname}){
		${classname}Service.save(${classname});

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
##    @RequiresPermissions("${moduleName}:${pathName}:update")
    public R update(@RequestBody ${className}Entity ${classname}){
		${classname}Service.updateById(${classname});

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
##    @RequiresPermissions("${moduleName}:${pathName}:delete")
    public R delete(@RequestBody ${pk.attrType}[] ${pk.attrname}s){
		${classname}Service.removeByIds(Arrays.asList(${pk.attrname}s));

        return R.ok();
    }

}

然后我们重新运行renren-generator生成代码替换掉controller即可

阶段复盘

  • 1、当多个maven项目有共同的依赖时,可以创建一个公共的maven项目,引入需要安装的依赖,这个maven项目专门管理这些公共的依赖,然后其他服务继承这个通用的maven服务即可。

  • 2、多服务项目可以利用maven聚合项目来管理,只需在顶级项目根目录的pom.xml文件中中声明modules并将子模块声明为module即可。在idea中右上角点击添加项目将项目根目录设置为root根目录后,在idea左下角即可一键启动全部服务idea右上角可针对所有子服务同时执行maven生命周期操作,参考

  • 3、当开始一个新的项目时,我们可以使用逆向工程(代码生成)快速生成针对单表增删改查的业务代码(业务层、控制层、Dao层),减少70%的代码开发工作。

  • 4、之后在开发所有的微服务两个步骤:(1)、先让其依赖gulimall-common公共依赖项目(2)、使用逆向工程生成其基本的增删改查代码。

  • 5、docker常用命令操作

docker pull image // 拉取镜像文件

docker images // 缓查看当前已安装的镜像文件

sudo systemctl start docker // 启动docker

sudo systemctl enable docker  // 设置docker开机自启

docker exec -it 容器id或者容器名称 /bin/bash // 进入容器

docker start 容器id或者容器名称 // 启动容器

docker restart 容器id或者容器名称 // 重启容器

docker logs 容器id或者容器名称 // 查看容器日志

docker ps -a // 查看容器运行状态

docker exec -it redis redis-cli // 执行redis-cli连接

docker update redis --restart=always // 设置开机自动运行redis容器,目的是防止虚拟器重启以后redis服务未启动

docker exec -it mysql mysql -uroot -p // 通过容器的 mysql 命令行工具连

配置&测试微服务的基本CURD功能

要测试微服务的基本curd功能我们需要整合mybatis-plus插件

整合mybatis-plus插件

整合mybatis-plus插件步骤如下:

  • 1、导入依赖 由于我们每个微服务项目都有用到mybatis-plus的插件,所以我们可以统一在gulimall-commonpom文件中导入依赖

gulimall-common/pom.xml

xml
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.2.0</version>
</dependency>
  • 2、配置数据源

(1)、导入数据库驱动

注意:选择启动一定要根据当前mysql的版本来找支持该版本的数据库驱动,官方说明8.0和5.0版本的mysql驱动都是支持mysql5.7

mysql驱动同样每个微服务均有用到,所以统一在gulimall-commonpom文件中引入mysql驱动包

gulimall-common/pom.xml

xml
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.17</version>
</dependency>

(2)、在application.yml中配置数据源相关信息 gulimall-product/src/main/resources/application.yml

xml
spring:
  datasource:
    username: root
    password:
    url: jdbc:mysql://101.43.17.174:3306/gulimall_pms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

3、配置mybatis-plus

(1)、配置@MapperSacn注解

com/atguigu/gulimall/product/GulimallProductApplication.java

java
package com.atguigu.gulimall.product;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
    }

}

(2)、告诉mybatis-plussql映射文件位置 gulimall-product/src/main/resources/application.yml

xml
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml

(3)、配置主键自增 gulimall-product/src/main/resources/application.yml

xml
  global-config:
    db-config:
      id-type: auto

配置完成后的完整application.yml文件 gulimall-product/src/main/resources/application.yml

xml
spring:
  datasource:
    username: root
    password: Joezc123456
    url: jdbc:mysql://101.43.17.174:3306/gulimall_pms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto

spring整合mybatis-plus小结

整合mybatis-plus插件具体步骤:

  • 引入mybatis-plus依赖

  • 配置mybatis-plus

1、配置数据源

(1)、导入数据库驱动

(2)、在application.yml配置数据源相关信息

2、配置mybatis-plus信息

(1)、使用@MapperScan注解扫描mapper

(2)、配置mapper-location告诉mybatis-plus sql映射文件所在位置

编写CRUD代码测试整合是否成功

我们在单元测试类中编写测试代码 com.atguigu.gulimall.product.GulimallProductApplicationTests

java
package com.atguigu.gulimall.product;

import com.atguigu.gulimall.product.entity.BrandEntity;
import com.atguigu.gulimall.product.service.BrandService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class GulimallProductApplicationTests {

    @Autowired
    BrandService brandService;


    @Test
    void  contextLoads() {

        BrandEntity brandEntity = new BrandEntity();
        // 保存
        // brandEntity.setName("华为");
        // brandService.save(brandEntity);
        // System.out.println("保存成功");

        // 修改
        // brandEntity.setName("oppo");
        // brandEntity.setBrandId((long) 3);
        // brandEntity.setDescript("oppo 大品牌");
        // brandService.updateById(brandEntity);

        // 查询
        List<BrandEntity> list = brandService.list(new QueryWrapper<BrandEntity>().eq("name","oppo"));
        list.forEach((item) -> {
            System.out.println(item);
        });
    }

}

整合mybatis-plus过程中遇到的问题

在整合mybatis-plus过程中遇到了 java: 无法ora springtramework.beanstactoryannotation.Autowirec的错误,排查后发现:当使用SpringBoot3.0及以下版本时要求java版本17以上,spring生成器默认生成的项目使用的java版本是17,SpringBoot版本是3.0以上,但由于本机加载的jdk版本是8,所以导致这个错误,修改gulimall-product/pom.xml文件如下后解决错误。

gulimall-product/pom.xml

xml
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-product</name>
    <description>谷粒商城-商品服务</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

逆向工程生成其他模块代码

生成其他微服务服务基本代码

优惠服务对应的数据库表是gulimall-sms,接下来生成gulimall-coupon优惠服务基本代码

  • 1、修改renren-generator的配置文件

修改moduleNametablePrefix表前缀 renren-generator/src/main/resources/generator.properties

#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F

mainPath=com.atguigu
#\u5305\u540D
package=com.atguigu.gulimall
moduleName=coupon
#\u4F5C\u8005
author=zhaochao
#Email
email=1798231822@qq.com
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
tablePrefix=sms_

#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F
tinyint=Integer
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean

char=String
varchar=String
tinytext=String
text=String
mediumtext=String
longtext=String


date=Date
datetime=Date
timestamp=Date

NUMBER=Integer
INT=Integer
INTEGER=Integer
BINARY_INTEGER=Integer
LONG=String
FLOAT=Float
BINARY_FLOAT=Float
DOUBLE=Double
BINARY_DOUBLE=Double
DECIMAL=BigDecimal
CHAR=String
VARCHAR=String
VARCHAR2=String
NVARCHAR=String
NVARCHAR2=String
CLOB=String
BLOB=String
DATE=Date
DATETIME=Date
TIMESTAMP=Date
TIMESTAMP(6)=Date

int8=Long
int4=Integer
int2=Integer
numeric=BigDecimal

nvarchar=String

修改renren-generatorapplication.yml配置文件,修改需要生成代码的数据库地址

xml
server:
  port: 80

# mysql
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #MySQL配置
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://101.43.17.174:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: Joezc123456
    #oracle配置
    #    driverClassName: oracle.jdbc.OracleDriver
    #    url: jdbc:oracle:thin:@47.100.206.162:1521:xe
    #    username: renren
    #    password: 123456
    #SQLServer配置
    #    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
    #    url: jdbc:sqlserver://192.168.10.10:1433;DatabaseName=renren_fast
    #    username: sa
    #    password: 123456
    #PostgreSQL配置
  #    driverClassName: org.postgresql.Driver
  #    url: jdbc:postgresql://192.168.10.10:5432/renren_fast
  #    username: postgres
  #    password: 123456



  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  resources:
    static-locations: classpath:/static/,classpath:/views/

#mongodb:
#  host: localhost
#  port: 27017
#  auth: false #是否使用密码验证
#  username: tincery
#  password: renren
#  source: 123456
#  database: test

mybatis-plus:
  mapperLocations: classpath:mapper/**/*.xml


pagehelper:
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql


#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql、mongodb】
renren:
  database: mysql
  • 2、修改gulimall-couponpom配置文件,application.yum配置文件,修改spring版本和java版本,依赖gulimall-common

原本的gulimall-coupon/pom配置文件,此时spring版本依然是3.0,java版本是17,我们进行修改

修改后的pom配置文件如下 gulimall-coupon/pom.xml

xml
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-coupon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-coupon</name>
    <description>谷粒商城-优惠券服务</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

我们将之前配置好的gulimall-productpom.xml文件复制到gulimall-couponresource

gulimall-coupon/src/main/resources/application.yml

xml
spring:
  datasource:
    username: root
    password: 
    url: jdbc:mysql://101.43.17.174:3306/gulimall_sms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
  • 3、运行renren-genarator生成gulimall-coupon基本代码

配置修改完成后即可运行renren-generator生成基本代码

注意:这里初次启动项目失败,报java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException:

解决方案:将gulimall-commonpom文件中的servlet-api注释即可启动

xml
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>pro
    </scope>
</dependency>

启动项目后我们尝试访问服务,看是否正常

服务可正常访问

我们按照相同的方式生成其他模块,并且将:

gulimall-coupon端口设置为7000

gulimall-member端口设置为8000

gulimall-order端口为9000

gulimall-product端口为10000

gulimall-ware端口为11000

按照以上步骤生成各个微服务基本代码

Spring Cloud Alibaba

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用

微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布 式应用服务。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用

接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统

Spring Cloud的痛点

  • SpringCloud 部分组件停止维护和更新,给开发带来不便;

  • SpringCloud 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制

  • SpringCloud 配置复杂,难以上手,部分配置差别难以区分和合理应用

Spring Cloud Alibaba的优势

阿里使用过的组件经历了考验,性能强悍,设计合理,现在开源出来大家用

成套的产品搭配完善的可视化界面给开发运维带来极大的便利

搭建简单,学习曲线低

目前主流的SpringCloud技术方案

SpringCloud Alibaba - Nacos:注册中心(服务发现/注册)

SpringCloud Alibaba - Nacos:配置中心(动态配置管理)

SpringCloud - Ribbon:负载均衡

SpringCloud - Feign:声明式 HTTP 客户端(调用远程服务)

SpringCloud Alibaba - Sentinel:服务容错(限流、降级、熔断)

SpringCloud - GatewayAPI 网关(webflux 编程模式)

SpringCloud - Sleuth:调用链监控

SpringCloud Alibaba - Seata:原 Fescar,即分布式事务解决方

版本选择

由于 Spring Boot 1Spring Boot 2Actuator 模块的接口和注解有很大的变更,且spring-cloud-commons1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟SpringBoot 版本号一致的版本:

WARNING


在选择Spring Cloud相关组件版本时一定要需要参考SpringCloud Alibaba版本说明

由于目前项目使用的Spring Boot版本时2.3.12

添加Spring Cloud Alibabab项目依赖 gulimall-common/pom.xml

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.7.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
</dependencyManagement>

Spring Cloud接入Nacos

docker安装nacos

创建nacos_config数据库

创建数据库nacos_config,配置nacos数据库,方便观察运行时具体的数据

sql
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
 
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `src_user` text,
  `src_ip` varchar(20) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
 
 
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
 
 
CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
 
CREATE TABLE users (
    username varchar(50) NOT NULL PRIMARY KEY,
    password varchar(500) NOT NULL,
    enabled boolean NOT NULL
);
 
CREATE TABLE roles (
    username varchar(50) NOT NULL,
    role varchar(50) NOT NULL,
    constraint uk_username_role UNIQUE (username,role)
);
 
CREATE TABLE permissions (
    role varchar(50) NOT NULL,
    resource varchar(512) NOT NULL,
    action varchar(8) NOT NULL,
    constraint uk_role_permission UNIQUE (role,resource,action)
);
 
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
 
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

拉取镜像文件&修改配置

docker pull nacos/nacos-server

挂载目录 /mydata/nacos/init.d/custom.properties

mkdir -p /mydata/nacos/logs/                      #新建logs目录
mkdir -p /mydata/nacos/init.d/          
vim /mydata/nacos/init.d/custom.properties        #修改配置文件

配置文件修改如下

server.contextPath=/nacos
server.servlet.contextPath=/nacos
server.port=8848

spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://xx.xx.xx.x:3306/nacos_config? characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true #这里需要修改端口
db.user=user #用户名
db.password=pass #密码

nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i
nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/**
nacos.naming.distro.taskDispatchThreadCount=1
nacos.naming.distro.taskDispatchPeriod=200
nacos.naming.distro.batchSyncKeyCount=1000
nacos.naming.distro.initDataRatio=0.9
nacos.naming.distro.syncRetryDelay=5000
nacos.naming.data.warmup=true
nacos.naming.expireInstance=true

启动nacos容器

我们Spring Cloud Alibaba的版本是2.2.9.RELEASE,这里对应nacos版本需要选择的是v2.1.0版本

WARNING


在选择Spring Cloud相关组件版本时一定要需要参考SpringCloud Alibaba版本说明

docker run --name nacos \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v /mydata/nacos/logs:/home/nacos/logs \
-v /mydata/nacos/init.d/custom.properties:/home/nacos/init.d/custom.properties \
-d nacos/nacos-server:v2.1.0

设置nacos开机自动启动

docker update --restart=always  nacos

启动成功后浏览器访问部署服务器8848端口加nacos后缀

在工作中更好的方式是将启动nacos容器以及删除容器的docker命令都封装成sh命令,这样就能方便快捷启动容器

/usr/local/docker/nacos/start.sh

bash
#!/bin/bash

docker run --name nacos \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v /mydata/nacos/logs:/home/nacos/logs \
-v /mydata/nacos/init.d/custom.properties:/home/nacos/init.d/custom.properties \
-d nacos/nacos-server:v2.1.0

# 开机自启动
docker update --restart=always  nacos

/usr/local/docker/nacos/remove.sh

bash
#!/bin/bash

CONTAINER_NAME="nacos"

CONTAINER_ID=$(docker ps -aqf "name=^$CONTAINER_NAME\$")   # 获取指定容器的ID
if [ ! -z "$CONTAINER_ID" ]; then
    docker stop $CONTAINER_ID && docker rm $CONTAINER_ID   # 先停止再移除容器
fi

版权声明:本文为CSDN博主「xtldcn」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xtldcn/article/details/128867700

接入Nacos服务发现/注册中心

Spring Cloud Alibaba Nacos作为服务注册中心例子

1、引入Nacos Discovery Startergulimall-common/pom.xml

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2、配置Nacos Server地址

注意:需要配置了application.name服务才能显示

gulimall-coupon/src/main/resources/application.yml

yml
spring:
  datasource:
    username: root
    password: Joezc123456
    url: jdbc:mysql://101.43.17.174:3306/gulimall_sms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
  cloud:
    nacos:
      discovery:
        server-addr: 101.43.17.174:8848
   application:
     name: gulimall-coupon
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
server:
  port: 7000

3、启动类添加@EnableDiscoveryClient注解

com.atguigu.gulimall.coupon.GulimallCouponApplication

java
package com.atguigu.gulimall.coupon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@SpringBootApplication
@EnableDiscoveryClient
public class GulimallCouponApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallCouponApplication.class, args);
    }

}

4、查看服务

我们按照同样的步骤将gulimall-member服务也添加到注册中心

gulimall-member/src/main/resources/application.yml

yml
spring:
  datasource:
    username: root
    password: Joezc123456
    url: jdbc:mysql://101.43.17.174:3306/gulimall_ums?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
  cloud:
    nacos:
      discovery:
        server-addr: 101.43.17.174:8848
  application:
    name: gulimall-member
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
server:
  port: 8000

com.atguigu.gulimall.member.GulimallMemberApplication

java
package com.atguigu.gulimall.member;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class GulimallMemberApplication {
    public static void main(String[] args) {
        SpringApplication.run(GulimallMemberApplication.class, args);
    }

}

服务成功注册

WARNING

注意:在配置nacos的过程中nacos始终启动失败,多方查找都没找到报错原因,最后想起服务是部署在云服务器上的,除了要打开服务器上的防火墙外,还需要在腾讯云服务器上打开对应的防火墙。

接入Nacos过程小结

  • 1、添加nacos-discovery-starter依赖

  • 2、配置Nacos Server服务地址

  • 3、启动类添加@EnableDiscoveryClient注解

  • 4、访问Nacos后台服务查看已注册服务

Feign 声明式远程调用

Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了 HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。 Feign 整合了 Ribbon(负载均衡)和 Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。 SpringCloudFeignNetflixFeign 的基础上扩展了对 SpringMVC 注解的支持,在其实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了SpringCloudRibbon 自行封装服务调用客户端的开发量

Feign使用

假设现在gulimall-member需要调用gulimall-coupon服务,我们在gulimall-coupon优惠券服务中声明一个函数用来测试

com.atguigu.gulimall.coupon.controller.CouponController

java
package com.atguigu.gulimall.coupon.controller;

import java.util.Arrays;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.gulimall.coupon.entity.CouponEntity;
import com.atguigu.gulimall.coupon.service.CouponService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;



/**
 * 优惠券信息
 *
 * @author zhaochao
 * @email 1798231822@qq.com
 * @date 2023-05-16 21:45:55
 */
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    // 添加gulimall-coupon测试方法
    @RequestMapping("/member/list")
    public R membercoupons(){
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("满100减10");
        return R.ok().put("coupons", Arrays.asList(couponEntity));
    }
}

gulimall-coupon已提供了远程调用的方法,接下来gulimall-member如果想要远程调用该方法需要做以下操作

假设现在gulimall-member需要远程调用gulimall-coupon服务的远程方法,那么需要做如下步骤:

  • 1、引入openfeign依赖

之前创建Spring项目是已经引入了Feign依赖

gulimall-member/pom.xml

xml
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-member</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-member</name>
    <description>谷粒商城-会员服务</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 2、编写一个接口,告诉SpringBoot这个接口需要调用远程服务,声明接口每一方法都是调用哪个远程服务的哪个请求

我们创建一个feign的包来保存远程调用其他模块服务的接口,我们创建一个实例接口CouponFeignService

com.atguigu.gulimall.member.feign.CouponFeignService

java
package com.atguigu.gulimall.member.feign;

import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("gulimall-coupon")
public interface CouponFeignService {

    @RequestMapping("/coupon/coupon/member/list")
    public R membercoupons();
}

这段代码的意思是:如果以后我们调用该接口的membercoupons方法,那么这个方法将会去注册中心中寻找远程服务gulimall-coupon,然后调用该该服务的/coupon/coupon/member/list地址对应的方法。

  • 3、开启远程调用功能

gulimall-member所有远程调用的接口目前都放在了feign包下,我们需要在gulimall-member启动类添加上EnableFeignClients注解,并传入远程调用服务所在包名。

java
package com.atguigu.gulimall.member;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * 1、想要远程调用其他服务
 *
 */
@EnableFeignClients(basePackages = "com.atguigu.gulimall.member.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallMemberApplication {
    public static void main(String[] args) {
        SpringApplication.run(GulimallMemberApplication.class, args);
    }
}

声明该注解后,每次在我们启动gulimall-member服务后,都会扫描com.atguigu.gulimall.member.feign包下所有标了FeignClient注解的接口

配置已经完成,接下来需要测试下是否成功

  • 4、测试Feign是否调用成功

我们在com.atguigu.gulimall.member.controller.MemberController控制类添加如下测试方法:

com.atguigu.gulimall.member.controller.MemberController

java
package com.atguigu.gulimall.member.controller;

import java.util.Arrays;
import java.util.Map;

import com.atguigu.gulimall.member.feign.CouponFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.gulimall.member.entity.MemberEntity;
import com.atguigu.gulimall.member.service.MemberService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;



/**
 * 会员
 *
 * @author zhaochao
 * @email 1798231822@qq.com
 * @date 2023-05-17 21:29:32
 */
@RestController
@RequestMapping("member/member")
public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    CouponFeignService couponFeignService;

    /**
     * 添加一个测试方法,测试Feign是否调用成功
     * @return
     */
    @RequestMapping("/coupons")
    public R test(){
        MemberEntity memberEntity = new MemberEntity();

        memberEntity.setNickname("张三");

        R membercoupons = couponFeignService.membercoupons();

        return R.ok().put("member",memberEntity).put("coupons",membercoupons.get("coupons"));
    }
}

接下来我们分别启动gulimall-coupongulimall-member服务,然后浏览器访问http://localhost:8000/member/member/coupons地址,可以看到成功访问到数据

Feign使用小结

假设现在我们有一个服务A需要远程调用另一个远程服务B,我们需要在A服务中做如下配置

假设服务B已经声明了一个测试接口用来响应Feign的远程调用

我们需要在A服务中做如下配置

  • 1、引入OpenFeign依赖

  • 2、创建一个Feign包来保存远程调用其他服务的接口,Feign远程调用接口添加FeignClientRequestMapping注解

  • 3、开启远程调用功能,在启动类上添加EnableFeignClients注解,传入刚刚创建的用来保存远程调用服务的feign包的地址

  • 4、测试Feign调用远程服务是否成功

Nacos作为配置中心

Spring Cloud Alibaba官方Nacos 配置中心例子

  • 添加Nacos Config Starter依赖

后面每一个微服务都可能需要Nacos作为配置中心,所以我们在gulimall-common中引入相关依赖

gulimall-common/pom.xml

xml
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  • 添加Nacos配置

假设现在gulimall-coupon服务需要nacos作为配置中心来管理相关配置,我们需要在应用的gulimall-coupon/src/main/resources/bootstrap.properties配置文件中配置 Nacos Config 地址并引入服务配置:

gulimall-coupon/src/main/resources/bootstrap.properties

properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=101.43.17.174:8848
  • 测试Nacos作为配置中心

我们在gulimall-coupon/src/main/resources/application.properties中添加两个配置变量

gulimall-coupon/src/main/resources/application.properties

properties
coupon.user.name=zhangsan
coupon.user.age=18

然后我们在gulimall-coupon中添加一个测试接口,返回从配置文件中获取到的变量数据 com.atguigu.gulimall.coupon.controller.CouponController

java
package com.atguigu.gulimall.coupon.controller;

import java.util.Arrays;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.gulimall.coupon.entity.CouponEntity;
import com.atguigu.gulimall.coupon.service.CouponService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;



/**
 * 优惠券信息
 *
 * @author zhaochao
 * @email 1798231822@qq.com
 * @date 2023-05-16 21:45:55
 */
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    @Value("${coupon.user.name}")
    private String name;

    @Value("${coupon.user.age}")
    private Integer age;

    @RequestMapping("/test")
    public R test(){
        return R.ok().put("name",name).put("age",age);
    }
}

此时浏览器测试是可以正常访问的

现在nameage都可以正常访问,假设现在我们需要修改配置文件中的值,我们需要做如下步骤:

1、修改配置文件

2、修改后重新进行项目打包

3、将打包好的项目部署在服务器

这样的步骤非常麻烦,现在我们可以将这些配置交给配置中心,只需要在配置中心修改配置文件,所有微服务的配置就都可以动态改变,需要做如下配置。

  • 1、在项目启动控制台我们可以看到如下信息:

这里我们需要提取的信息是{name='bootstrapProperties-gulimall-coupon.properties,DEFAULT_GROUP'},我们需要记住这个name的值

  • 2、接下来我们访问Nacos后台服务,选择配置管理/配置列表菜单,点击右上角的添加按钮

我们将之前提取到的name值填入其中,并且将在项目的application.properties配置文件中配置的变量填入其中

WARNING

这里提取的name值不需要前面的bootstrapProperties前缀,即bootstrapProperties-gulimall-coupon.properties只需要提取gulimall-coupon.properties作为配置的Data ID即可

然后发布服务即可

  • 3、添加注解

com.atguigu.gulimall.coupon.controller.CouponController

java
package com.atguigu.gulimall.coupon.controller;

import java.util.Arrays;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.gulimall.coupon.entity.CouponEntity;
import com.atguigu.gulimall.coupon.service.CouponService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;



/**
 * 优惠券信息
 *
 * @author zhaochao
 * @email 1798231822@qq.com
 * @date 2023-05-16 21:45:55
 */
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    @Value("${coupon.user.name}")
    private String name;

    @Value("${coupon.user.age}")
    private Integer age;

    @RequestMapping("/test")
    public R test(){
        return R.ok().put("name",name).put("age",age);
    }
}

配置完成后我们现在继续访问gulimall-coupon之前添加的test接口http://localhost:7000/coupon/coupon/test

可以看到访问正常

接下来我们在nacos服务后台中动态修改配置文件,点击编辑按钮

我们修改配置文件信息,然后发布配置

接下来再访问gulimall-coupontest接口,可以看到此时的配置信息已经动态改变了!!!

Nacos接入配置中心小结

1、引入spring-cloud-starter-alibaba-nacos-config依赖

2、创建一个bootstrap.properties并添加Nacos地址等信息,并在application.properties配置文件中添加一些测试配置信息

3、将当前项目的数据集(bootstrap.properties,项目启动时可以看到)添加到Nacos后台服务中,并将当前的application.properties配置文件信息添加到Nacos后台服务中

4、在需要动态获取到配置的类中添加@Value@RefreshScope注解

5、启动项目,在Nacos后台服务中动态修改配置文件,浏览器访问服务,测试配置文件是否已动态修改

Nacos配置中心进阶

命名空间

用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 GroupData ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

假设我们项目一共有三套环境:本地环境、测试环境、生产环境,我们可以在Nacos配置中心配置多套命名空间,项目在打包时指定使用哪套命名空间,项目运行时即可读取指定命名空间的配置信息,具体配置如下:

  • 1、我们在Nacos后台服务中分别创建devtestprop三个命名空间
  • 2、我们切换到配置列表奥菜单,分别在三个命名空间创建与之前在public命名空间一样的配置
  • 3、在gulimall-coupongulimall-coupon/src/main/resources/bootstrap.properties文件中指定当前使用的命名空间

gulimall-coupon/src/main/resources/bootstrap.properties

properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=101.43.17.174:8848
spring.cloud.nacos.config.namespace=95b00afd-6145-462c-8527-21df11b586d2

WARNING

注意:指定的是对应的命名空间ID

此时我们再访问之前写好的测试接口,可以发现此时的配置信息已经是test命名空间对应的配置信息了

我们不仅可以通过项目环境区分,也可以通过微服务区分命名空间

配置集

一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。

配置集ID

Nacos 中的某个配置集的 ID。配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有 意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。

配置分组

Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 BuyTrade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。

配置分组默认是DEFAULT_GROUP

注意:命名空间和配置分组最佳的实践是以微服务区分命名空间,以开发环境区分配置分组,这样就可以将每个微服务的每个开发环境都进行隔离。

我们在创建配置时可以指定配置分组,我们这里以开发环境devtestprop指定项目环境作为配置分组

gulimall-coupongulimall-coupon/src/main/resources/bootstrap.properties文件中指定当前使用的配置分组,这里使用的是dev分组

gulimall-coupon/src/main/resources/bootstrap.properties

properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=101.43.17.174:8848
spring.cloud.nacos.config.namespace=51a0ead9-0586-4fd3-99af-503997983eac
spring.cloud.nacos.config.group=dev

这里相当于获取到了gulimall-coupon微服务下的dev环境的项目配置信息

这样既可区分微服务以及它的项目环境

加载多个配置集

在实际的开发过程中,随着业务的不断壮大,我们不会将所有的配置都写在这一个配置文件中,这样后期的维护难度较高。正常的做法是拆分配置文件,例如跟数据源相关的,或者框架相关的全部拆分出来。

gulimall-coupon/src/main/resources/application.yml

yml
spring:
  datasource:
    username: root
    password: Joezc123456
    url: jdbc:mysql://101.43.17.174:3306/gulimall_sms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
  cloud:
    nacos:
      discovery:
        server-addr: 101.43.17.174:8848
  application:
    name: gulimall-coupon
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
server:
  port: 7000
  • 1、抽离配置集

我们首先将数据源相关的配置抽离出来,并在nacos后台创建对应的服务,使用dev分组

将数据源相关的配置抽离在datasource.yml

mybatis-plus相关的配置抽离在mabatis.yml

将其他的配置抽离在other.yml

  • 2、配置同时加载多个配置集

我们修改boostrap.properties配置文件

gulimall-coupon/src/main/resources/bootstrap.properties

properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=101.43.17.174:8848
#加载当前自己的服务
spring.cloud.nacos.config.namespace=51a0ead9-0586-4fd3-99af-503997983eac
#spring.cloud.nacos.config.group=dev

spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true

spring.cloud.nacos.config.extension-configs[1].data-id=other.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true

spring.cloud.nacos.config.extension-configs[2].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

接下来我们注释原本的配置,重新启动项目

gulimall-coupon/src/main/resources/application.yml

xml
#spring:
#  datasource:
#    username: root
#    password: Joezc123456
#    url: jdbc:mysql://101.43.17.174:3306/gulimall_sms?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
#  cloud:
#    nacos:
#      discovery:
#        server-addr: 101.43.17.174:8848
#  application:
#    name: gulimall-coupon
#mybatis-plus:
#  mapper-locations: classpath:/mapper/**/*.xml
#  global-config:
#    db-config:
#      id-type: auto
#server:
#  port: 7000

我们访问测试地址,可以发现加载的数据并不是nacos服务中的,而是本地配置,这是因为我们在bootstrap.properties未声明配置加载的分组,所以默认访问的是DEFAULT_GROUP分组,但我们前面已经删除该分组,nacos服务找不到该分组配置集,所以加载到了项目本地配置信息

WARNING

注意:配置中心中有的配置优先使用配置中心的配置,没有的话就加载本地配置

gulimall-coupon/src/main/resources/application.properties

properties
coupon.user.name=zhangsan
coupon.user.age=18

我们修改设置group后刷新浏览器测试

gulimall-coupon/src/main/resources/bootstrap.properties

properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=101.43.17.174:8848
#加载当前自己的服务
spring.cloud.nacos.config.namespace=51a0ead9-0586-4fd3-99af-503997983eac
spring.cloud.nacos.config.group=prop

spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true

spring.cloud.nacos.config.extension-configs[1].data-id=other.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true

spring.cloud.nacos.config.extension-configs[2].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

可以发现配置正常

再测试下我们配置的datasource数据源和mybatis是否正常,我们访问gulimall-coupon现有的接口服务,查询数据库,可以看到数据正常,证明配置生效

Nacos配置中心小结

  • 1、命名空间主要的作用是环境隔离

  • 2、需要在bootstrap.properties配置文件中声明需要使用哪个命名空间

  • 3、我们不仅可以根据项目环境区分命名空间,也可以通过微服务来区分命名空间

  • 4、namespacegroup 最佳实践:每个微服务创建自己的 namespace 进行隔离,group 来区分 dev,beta,prod 等项目环境,这样即可精确隔离控制每个微服务和它们各自的项目环境

  • 5、同时加载多个配置集,只需要在bootstrap.properties中说明加载配置中心中哪些配置文件

  • 6、可以发现微服务中application.propertiesapplication.yml配置文件内容都可以在配置中心中配置,最终微服务只需要保留bootstrap.properties配置文件即可

目前开发期间为了方便先声明在本地项目的yml配置文件中

上次更新于: