接下来把网关和配置中心放一块说说,为啥放一块说呢,因为这俩玩意和服务注册中心一样,里头也不会写实际业务类代码。
看上头的项目结构,因为是跟着课程看的,所以组件是被细化成模块来开发了,等做实际业务开发时,像上面的那几个client都应该是一概没有的,模块就应该缩减为:服务注册中心、各种微服务(里面带有openFeign、Hystrix、Config等一些组件的相关内容)、熔断器仪表盘、网关、配置中心这几个大模块,做集群的话模块就更多,当然我这里比较省事,直接在VMoptions里用 -Dserver.port起多服务来测试了。
一、Config组件
上图为概念,简单来说就是比如我在一个微服务的配置文件里写了数据库配置,有一天数据库地址变了,使用配置中心统一管理的话就不用去微服务中再去修改配置文件再重启了,只需要在远程托管平台修改配置文件内容然后刷新配置即可,刷新的话这节就说一下手动刷新,实现自动刷新要用BUS控制总线,下节再写。
如图,首先需要有一个config服务端,可以让config客户端(就是微服务)进行注册,这点类似于服务注册中心(但是configserver也要注册在服务注册中心嗷),同时configserver要声明远程库地址,作为一个configclient获取配置文件的中转站。
开发configserver非常简单,老套路,引依赖、写配置、加注解。
<!--引入统一配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
#指定服务端口
server.port=8848
#指定服务名称
spring.application.name=CONFIGSERVER
#consul server 服务注册地址
spring.cloud.consul.discovery.hostname=localhost
spring.cloud.consul.port=8500
#执行注册当前服务的服务名称 默认:${spring.application.name}
spring.cloud.consul.discovery.service-name=${spring.application.name}
#远程仓库地址
spring.cloud.config.server.git.uri=https://gitee.com/xxxxxxxxx
spring.cloud.config.server.git.default-label=master
#要是私有库需要写用户名密码
#spring.cloud.config.server.git.username= 私有仓库访问用户名
#spring.cloud.config.server.git.password= 私有仓库
@EnableConfigServer //代表我是统一配置中心服务
看依赖这个组件应该是Spring公司的吧,我记得这个件说是耐非的或者Spring的都行。
我这里是往托管库放了三个配置文件,注意库要设公共,要是私有库不用密码启动,启动configserver会报错。
然后开发configclient端,其实这都应该正常写在微服务里的,但是为了测试,我就直接在client democontroller 中输出了一个取@Value ,比较直观。不错,连加注解都省了,只需要引依赖,写配置,注意:不是微服务没有配置文件,而是必须要有配置文件去指定获取仓库内容,要注册到哪个配置中心(因为配置中心要是做负载的话,那也需要通过ribbon获取service-id)等等。
<!--引入config client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
#config server 地址
#告诉当前configclient统一配置中心在注册中心服务id
spring.cloud.config.discovery.service-id=CONFIGSERVER
#开启当前configclient 根据服务id去注册中心获取
spring.cloud.config.discovery.enabled=true
#指定服务名称
spring.application.name=CONFIGCLIENT
#consul server 服务注册地址
spring.cloud.consul.discovery.hostname=localhost
spring.cloud.consul.port=8500
#执行注册当前服务的服务名称 默认:${spring.application.name}
spring.cloud.consul.discovery.service-name=${spring.application.name}
#获取哪个配置文件 1.确定分支 2.确定文件名 3.确定环境
spring.cloud.config.label=master
spring.cloud.config.name=configclient
spring.cloud.config.profile=prod
#开启所有web端点暴露
management.endpoints.web.exposure.include=*
从这个配置文件看,我要获取的是configclient-prod的配置文件,并且也没声明启动端口,因为端口在client.properties这个公共配置里,也会被拉下来使用
那么启动这个configclient。可以从启动日志发现,configserver去远程仓库先把配置文件拉取到本地路径,而且configclient已经读到了这两个配置文件,启动端口为7878,用postman请求接口获取到配置文件中写的value:
那么同理,我要是把configclient配置文件中的
spring.cloud.config.profile=prod
改成dev,那么取到的name就是dev文件中的内容。
configclient启动时报错要注意:
改成bootstrap.properties就好了,他的优先级应该比application高,这里用application起好像会去找默认的configserver的localhost:8888端口
最后就是Config组件的手动刷新,需要写配置、加注解、改远程库内容、curl
#开启所有web端点暴露
management.endpoints.web.exposure.include=*
@RefreshScope //作用:RefreshScope 用来在不需要重启微服务情况下,将当前scope域中信息刷新为最新配置信息
curl -X POST http://localhost:7878/actuator/refresh
注意:1、@RefreshScope要是配置文件中的值被多个类使用了,那就要在这几个类上都加这个注解 2、curl能用postman来换。
那么我现在把prod文件的name改了,curl一下,return内容变成金龙鱼了
二、网关组件
我最讨厌的组件了,没有之一,因为yml。。。而且网关和配置这块不用写啥代码,规则性较强,比较枯燥
那就少写点,这个组件我也是走着神听得,边听在编做其他事。
简单分析,耐非的zuul2.x也不行了,所以我就去用Spring的Gateway吧!
其特性:
- 基于springboot2.x 和 spring webFlux 和 Reactor 构建 响应式异步非阻塞IO模型
- 动态路由
- 请求过滤
webFlux是啥,响应式编程吧,可以去看看松哥讲的,Gateway实现的最终三点就是统一、转发(路由规则)
拦截,那一个一个说。
首先引依赖、写配置,不用加启动注解,配置最好写yml,因为网关涉及的规则太多了,properties得乱skr人,还有一点要注意,要把springbootweb的依赖去了,要不启动报错会和webFlux冲突
<!--引入gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--引入springbootweb 网关中不能使用springmvc的 web模型-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
server:
port: 7979
spring:
application:
name: GATEWAY
cloud:
consul:
host: localhost
port: 8500
gateway:
#路由转发规则
routes:
- id: category_router #路由对象唯一标识
# uri: http://localhost:8787/ #用来写类别服务地址 http://localhost:8787/category
uri: lb://CATEGORY #实现请求负载均衡处理
predicates: #断言 用来配置路由规则
- Path=/category
- id: product_router #路由对象唯一标识
# uri: http://localhost:8789/ #用来写商品服务地址 http://localhost:8789/list
uri: lb://PRODUCT #实现请求负载均衡处理
predicates: #断言 用来配置路由规则
- Path=/list,/product #支持通配符 /product/**
# - Method=GET #限定指定请求方式可用
# - After=2020-07-21T11:39:33.993+08:00[Asia/Shanghai] #指定日期之后的请求进行路由
# - Cookie=username,[A-Za-z0-9]+ #基于指定cookie的请求进行路由
# - Header=X-Request-Id, \d+ #基于请求头中的指定属性的正则匹配路由(这里全是整数)
# filters:
#这里的场景就是:各开两个类别服务,端口8786,8787(设为1,2)商品服务,端口8789,8790(设为3,4) 访问网关http://localhost:7979/category的话
#访问顺序为 13;24;14;23的轮询机制
#lb:loadbalance 的缩写
#不同断言类型是基于RoutePredicateFactory接口下的实现类
索性所有yml都贴出来了,还没写filter的规则,我真想讲C语言了(WORD很大,你要忍一下),我草,看没括号的缩进就烦,烦内。
这里我也说不清,也不太懂,统一的概念就是我访问localhost:7979/category这个地址其实就是去访问另外那个微服务的这个接口地址,同时这也是路径断言,也是路由规则转发,而且配置文件里根据ribbon找service-id做了负载,具体实现机制看配置文件最下头的注释,我模拟过了
路由规则转发中的断言还有cookie断言(要用curl)、时间断言、请求头断言等等等。
而且可以写java代码来配置路由规则,写配置类然后注入Bean就完事了,而且优先级是不是还高于yml配置啊,但是写起来比较麻烦,还是算了,虽然yml看着也挺麻烦。
统一和路由(比较关键的就是断言和负载均衡)都说了,拦截filter,也可以写在yml中,当然写配置类自定义filter也可以。
不想写了啦。😴