微服务项目搭建:Nacos以及GateWay配置

1,176 阅读7分钟

Nacos

为什么要在Nacos进行配置?

方便管理,不用重启项目就可以更改配置。如果微服务的实例多了,里面的配置可以方便统一管理。

配置三要素

搭建完成Nacos服务发现中心,下边搭建Nacos为配置中心,其目的就是通过Nacos去管理项目的所有配置。

先将项目中的配置文件分分类:

1、每个项目特有的配置

是指该配置只在有些项目中需要配置,或者该配置在每个项目中配置的值不同。

比如:spring.application.name每个项目都需要配置但值不一样,以及有些项目需要连接数据库而有些项目不需要,有些项目需要配置消息队列而有些项目不需要。

2、项目所公用的配置

是指在若干项目中配置内容相同的配置。比如:redis的配置,很多项目用的同一套redis服务所以配置也一样。swagger的配置,log的配置等等

另外还需要知道nacos如何去定位一个具体的配置文件,即:namespace、group、dataid.

1、通过namespace、group找到具体的环境和具体的项目。

2、通过dataid找到具体的配置文件,dataid有三部分组成

比如:content-service-dev.yaml配置文件 由(content-service)-(dev). (yaml)三部分组成

content-service:第一部分,它是在application.yaml中配置的应用名,即spring.application.name的值。

dev:第二部分,它是环境名,通过spring.profiles.active指定,

Yaml: 第三部分,它是配置文件 的后缀,目前nacos支持properties、yaml等格式类型,本项目选择yaml格式类型。

所以,如果我们要配置content-service工程的配置文件:

在开发环境中配置content-service-dev.yaml

在测试环境中配置content-service-test.yaml

在生产环境中配置content-service-prod.yaml

我们启动项目中传入spring.profiles.active的参数决定引用哪个环境的配置文件,例如:传入spring.profiles.active=dev表示使用dev环境的配置文件即content-service-dev.yaml。

3.配置优先级

如果本地的配置和nacos的配置文件有冲突,那么,以谁的为主?

应用场景:该工程在开发环境启动一个实例,又由于开发需要,在启动一个实例,需要更改端口,但是只是开发需要,去改nacos不合理,这时候就适合在本地改动配置。

到目前为止已将所有微服务的配置统一在nacos进行配置,用到的配置文件有本地的配置文件 bootstrap.yaml和nacos上的配置文件,SpringBoot读取配置文件 的顺序如下:

image.png

引入配置文件的形式有:

1、以项目应用名方式引入

2、以扩展配置文件方式引入

3、以共享配置文件 方式引入

4、本地配置文件

1,2,3都在nacos。4在本地

各配置文件 的优先级:项目应用名配置文件 > 扩展配置文件 > 共享配置文件 > 本地配置文件。

有时候我们在测试程序时直接在本地加一个配置进行测试,比如下边的例子:

我们想启动两个内容管理微服务,此时需要在本地指定不同的端口,通过VM Options参数,在IDEA配置启动参数。

image.png

通过-D指定参数名和参数值,参数名即在bootstrap.yml中配置的server.port。

启动ContentApplication2,发现端口仍然是63040,这说明本地的配置没有生效。

这时我们想让本地最优先,可以在nacos配置文件 中配置如下即可实现。

再次启动ContentApplication2,端口为63041。

配置本地优先:

#配置本地优先
spring:
 cloud:
  config:
    override-none: true

之后再创建实例的时候,可以通过添加参数的方式去配置端口等。

如何灵活的切换配置文件?

传参:

image.png

spring.profiles.active=test还是dev还是prod等

实例

特有配置
spring:
  application:
    name: content-api #服务名称
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
    username: root
    password: mysql
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: devNeu
        group: xuecheng-plus-project

这里在配置的时候,服务名称,server-addr和group,namespace都不能配到ncaos里,因为如果配置走,本地将无法发现nacos里的服务。

所以

  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: devNeu
        group: xuecheng-plus-project
   
    application:
    name: content-api #服务名称

不能配置到nacos的配置文件里。

需要拼装配置文件的例如content-api-dev.yaml里的东西在本地都不能删除。

本地配置的时候不要忘了配置config

注意区分profiles下的active的dev和自己的namespace里的

要注意区分服务注册发现和服务配置文件的信息。

spring:
  application:
    name: content-api #服务名称
#  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
#    username: root
#    password: mysql
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery: #服务注册发现的相关配置
        namespace: devNeu
        group: xuecheng-plus-project
      config: #配置文件的相关信息
        namespace: devNeu #我的命名空间,无论是配置也好,服务也好,都在我的命名空间下
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
  profiles:
    active: dev #环境名,拼接配置文件用的

注意对应配置文件的依赖

如果想用注册,就加discovery,如果想用配置中心,就加config

<!--        上报服务nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency><!--        nacos配置依赖-->
<!--        微服务里有一个配置的客户端,去nacos定时的拉取配置-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

结果:

2023-10-21 14:11:44,739 DEBUG [com.alibaba.nacos.client.Worker.longPolling.fixed-192.168.101.65_8848-devNeu][NacosRestTemplate.java:476] - HTTP method: POST, url: http://192.168.101.65:8848/nacos/v1/cs/configs/listener, body: {Listening-Configs=content-api-dev.yaml•xuecheng-plus-project•b1560ddf63798a362c47f567fa2516e2•devNeu•content-api.yaml•xuecheng-plus-project••devNeu•content-api•xuecheng-plus-project••devNeu•, tenant=devNeu}
2023-10-21 14:11:44,739 DEBUG [com.alibaba.nacos.client.Worker.longPolling.fixed-192.168.101.65_8848-devNeu][NacosRestTemplate.java:494] - Execute via interceptors :[com.alibaba.nacos.client.config.impl.ConfigHttpClientManager$LimiterHttpClientRequestInterceptor@403264c2]
2023-10-21 14:11:44,759 DEBUG [com.alibaba.nacos.client.Worker.longPolling.fixed-192.168.101.65_8848-devNeu][NacosRestTemplate.java:476] - HTTP method: POST, url: http://192.168.101.65:8848/nacos/v1/cs/configs/listener, body: {Listening-Configs=content-api-dev.yaml•xuecheng-plus-project•b1560ddf63798a362c47f567fa2516e2•devNeu•content-api.yaml•xuecheng-plus-project••devNeu•content-api•xuecheng-plus-project••devNeu•, tenant=devNeu}

从nacos里拿配置

接口层本身是不需要配置数据库的,但是他依赖着service层的代码,当打包启动的时候,就将service的mapper,service等代码全部依赖到接口层工程,接口层本身是不需要数据库连接的。

所以,在service层里配置数据库,在接口层去引用service工程的

service模块下的test里的bootstrap.yml里配置:

spring:
  application:
    name: content-service #服务名称
  #  datasource:
  #    driver-class-name: com.mysql.cj.jdbc.Driver
  #    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
  #    username: root
  #    password: mysql
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      config: #配置文件的相关信息
        namespace: devNeu #我的命名空间,无论是配置也好,服务也好,都在我的命名空间下
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
  profiles:
    active: dev #环境名,拼接配置文件用的
#  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
#    username: root
#    password: mysql

# 日志文件配置路径
logging:
  config: classpath:log4j2-dev.xml

我们的接口工程里不需要直接配置数据库,而是去引用service的。

api工程没有数据库连接,api的nacos文件里也没有。

#nacos配置里也注释掉datasource
server:
  servlet:
    context-path: /content
  port: 63040
# spring:
#   datasource:
#     driver-class-name: com.mysql.cj.jdbc.Driver
#     url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
#     username: root
#     password: mysql

api工程里用扩展引用

#发送请求的时候,自带/content内容,这个服务里就不用再写了
#server:
#  servlet:
#    context-path: /content
#  port: 63040
#微服务配置
spring:
  application:
    name: content-api #服务名称
#  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
#    username: root
#    password: mysql
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery: #服务注册的相关配置
        namespace: devNeu
        group: xuecheng-plus-project
      config: #配置文件的相关信息
        namespace: devNeu #我的命名空间,无论是配置也好,服务也好,都在我的命名空间下
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        extension-configs:
          - data-id: content-service-${spring.profiles.active}.yaml
            group: xuecheng-plus-project
            refresh: true

  profiles:
    active: dev #环境名,拼接配置文件用的
# 日志文件配置路径
logging:
  config: classpath:log4j2-dev.xml

swagger:
  title: "学成在线内容管理系统"
  description: "学成在线内容管理系统接口文档"
  base-package: com.xuecheng.content
  version: 1.0.0
  enabled: true


里的部分

        extension-configs:
          - data-id: content-service-${spring.profiles.active}.yaml
            group: xuecheng-plus-project
            refresh: true

  profiles:
    active: dev #环境名,拼接配置文件用的

service的nacos里的配置:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
    username: root
    password: mysql

api接口工程重启,如果能正常查询数据库,则证明配置成功。

当一个服务想要依赖另一个服务里的配置的时候,可以考虑用extension-configs:

公用配置

logging,swagger等。

公用配置,group可以当成项目名字或者分类。

#logging
# 日志文件配置路径
logging:
  config: classpath:log4j2-dev.xml
swagger:
  title: "学成在线项目结构文档"
  description: "学成在线内容管理系统接口文档"
  base-package: com.xuecheng
  version: 1.0.0
  enabled: true

都配置到nacos里的新建公共分组xuecheng-plus-common里

image.png

本地配置:

#发送请求的时候,自带/content内容,这个服务里就不用再写了
#server:
#  servlet:
#    context-path: /content
#  port: 63040
#微服务配置
spring:
  application:
    name: content-api #服务名称
#  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://192.168.101.65:3306/xcplus_content?serverTimezone=UTC&userUnicode=true&useSSL=false&
#    username: root
#    password: mysql
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery: #服务注册的相关配置
        namespace: devNeu
        group: xuecheng-plus-project
      config: #配置文件的相关信息
        namespace: devNeu #我的命名空间,无论是配置也好,服务也好,都在我的命名空间下
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        extension-configs:
          - data-id: content-service-${spring.profiles.active}.yaml
            group: xuecheng-plus-project
            refresh: true
        shared-configs: #共享文件,nacos里
          - data-id: swagger-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

  profiles:
    active: dev #环境名,拼接配置文件用的

新增:

shared-configs:
          - data-id: swagger-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true

网关配置

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>com.xuecheng</groupId>
        <artifactId>xuecheng-plus-parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../xuecheng-plus-parent</relativePath>
    </parent>
    <artifactId>xuecheng-plus-gateway</artifactId>
​
    <dependencies>
​
        <!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
​
        <!--服务发现中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- 排除 Spring Boot 依赖的日志包冲突 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
​
        <!-- Spring Boot 集成 log4j2 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
​
​
    </dependencies>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties></project>

本地:

yml配置:

#微服务配置
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: devNeu
        group: xuecheng-plus-project
      config:
        namespace: devNeu
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        shared-configs:
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
  profiles:
    active: dev

nacos中:

gateway-dev.yaml

  • Path=/content/** # 这个是按照路径匹配,只要以/content/开头就符合要求,都会路由到id值(例如content-api)的微服务。
server:
  port: 63010 # 网关端口
spring:
  cloud:
    gateway:
#      filter:
#        strip-prefix:
#          enabled: true
      routes: # 网关路由配置
        - id: content-api # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://content-api # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/content/** # 这个是按照路径匹配,只要以/content/开头就符合要求,都会路由到id值的微服务。
#          filters:
#            - StripPrefix=1
        - id: system-api
          # uri: http://127.0.0.1:8081
          uri: lb://system-api
          predicates:
            - Path=/system/**
#          filters:
#            - StripPrefix=1
        - id: media-api
          # uri: http://127.0.0.1:8081
          uri: lb://media-api
          predicates:
            - Path=/media/**
#          filters:
#            - StripPrefix=1
        - id: search-service
          # uri: http://127.0.0.1:8081
          uri: lb://search
          predicates:
            - Path=/search/**
#          filters:
#            - StripPrefix=1
        - id: auth-service
          # uri: http://127.0.0.1:8081
          uri: lb://auth-service
          predicates:
            - Path=/auth/**
#          filters:
#            - StripPrefix=1
        - id: checkcode
          # uri: http://127.0.0.1:8081
          uri: lb://checkcode
          predicates:
            - Path=/checkcode/**
#          filters:
#            - StripPrefix=1
        - id: learning-api
          # uri: http://127.0.0.1:8081
          uri: lb://learning-api
          predicates:
            - Path=/learning/**
#          filters:
#            - StripPrefix=1
        - id: orders-api
          # uri: http://127.0.0.1:8081
          uri: lb://orders-api
          predicates:
            - Path=/orders/**
#          filters:
#            - StripPrefix=1

503报错: 服务不可用。

服务不是立即启动完毕,nacos就可以发现服务,需要等30s以上,有一个窗口期。