Spring Cloud系列(二)——实践
搭建账单微服务工程
账单工程(bill)是我之前的一个spring boot项目,以下是将其重构为spring cloud项目的过程
0. 建一个空工程spring-cloud-bill便于管理各个微服务
1. 创建EurekaServer
-
在刚刚的空工程下新建一个module,选择Spring Initializr——starter service URL:如果default选项点击下一步后需要等很久可以使用自定义地址:
https://start.springboot.io
-
指定springboot版本,然后选择依赖:
Spring Boot DevTools、 Lombok
Eureka Server
-
完成创建后将application.properties的后缀改为yml,并进行如下配置:
server: port: 9010 # 服务运行的端口号 spring: application: name: eureka-server # 服务名称(唯一) eureka: client: service-url: defaulteZone: http://localhost:9010/eureka # 配置Eureka Server的地址,注意/eureka不可更改 register-with-eureka: false # 不注册自己,默认为true,如果这里不配置为false,会报错:Cannot execute request on any known server fetch-registry: false # 不拉取服务
-
启动器
@SpringBootApplication @EnableEurekaServer // 声明当前应用为Eureka Server public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
-
启动并测试
启动后访问http://localhost:9010,可以看到eureka管理界面:
红色警告是eureka的自我保护机制:如果Eureka Server接收到的服务续约低于配置的百分比阈值(默认为15分钟内低于85%),则服务器开启自我保护模式,即不再剔除注册列表的信息。
1. 创建Spring Cloud项目
-
在刚刚工程下再新建一个module,还是选择spring initializr
-
指定springboot版本,然后选择依赖:
Spring Boot DevTools、 Lombok
Eureka Discovery Client
-
给module取名为bill_service
-
初始化好后,将application.properties的后缀改为yml,并进行如下配置:
server: port: 9001 # 服务运行的端口号 spring: application: name: bill-service # 服务的名称(唯一),若eureka没有指定instance-id,则服务名称会作为eureka服务注册时的id # 连接池 datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: password url: jdbc:mysql://127.0.0.1:3306/bill-manager?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 eureka: client: service-url: defaultZone: http://localhost:9010/eureka # 配置eureka服务的地址,注意/eureka是固定的,不可以自定义 # 整合mybatis mybatis: type-aliases-package: com.xj.pojo # mybatis别名扫描 mapper-locations: classpath:/mybatis/*.xml # 指定mapper文件路径 logging: level: com.xj: debug # debug模式
-
启动器
@SpringBootApplication @MapperScan("com.xj.dao") @EnableDiscoveryClient public class BillServiceApplication { public static void main(String[] args) { SpringApplication.run(BillServiceApplication.class, args); } }
-
由于我是重构之前的spring boot项目,因此我直接将其他的文件也复制过来了。controller中写了一些接口,如/bill/list、bill/add等,下面展示/bill/list接口:
@RequestMapping("bill/list") public ResponseEntity list() { List<Bill> list = billService.list(new Bill()); return ResponseEntity.ok(list); // 返回json数据 }
-
启动并测试
启动后访问http://localhost:9001/bill/list,可以看到数据库查出的json格式数据:
启动后访问http://localhost:9010,可以看到eureka管理界面中已经有bill-service服务了:
2. 创建网关服务
-
在刚刚工程下再新建一个module,还是选择spring initializr
-
指定springboot版本,然后选择依赖:
Eureka Discovery Client
Spring Cloud Gateway
Resilience4J (用于配置熔断降级)
-
跨域访问问题:
前后端分离的项目中,前端项目单独运行,通过网关api来访问微服务,此时存在跨域访问的问题。
跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。即当访问的url中协议、ip地址、端口有任何一个与当前项目运行的url不同时,由于安全问题,这种请求会受到同源策略限制,会报跨域资源共享(CORS,Cross-origin resource sharing)错误。
为了避免开发的应用收到限制,可以在网关统一配置跨域访问。
-
修改配置文件
server: port: 8086 spring: application: name: api-gateway cloud: gateway: globalcors: # 跨域配置 cors-configurations: '[/**]': # 针对所有请求 max-age: 3600 allowed-origin-patterns: "*" # spring boot2.4配置 allowed-headers: "*" allow-credentials: true allowed-methods: # 请求方式 - GET - POST - DELETE - PUT - OPTION routes: # 路由配置 - id: bill_list # id中不能出现-!!!!!否则不生效 # uri: lb://bill-service # 负载均衡:lb://服务名称;当运行多个bill-service服务时,默认会轮询访问 uri: http://127.0.0.1:9001 predicates: - Path=/api/bill/list filter: - StripPrefix=1 # - name: CircuitBreaker # 熔断器 # args: # name: backendA # fallbackUri: forward:/fallbackA # 降级访问的路径 - id: bill_add uri: lb://bill-service predicates: - Path=/api/bill/add - Method=POST default-filters: # 统一配置过滤器 - StripPrefix=1 # 跳过第一个路径,例如:/api/bill/add 变为 /bill/add eureka: client: service-url: defaultZone: http://127.0.0.1:9010/eureka resilience4j: # 熔断降级 circuitbreaker: configs: default: failureRateThreshold: 30 #失败请求百分比,超过这个比例,CircuitBreaker变为OPEN状态 slidingWindowSize: 10 #滑动窗口的大小,配置COUNT_BASED,表示10个请求,配置TIME_BASED表示10秒 minimumNumberOfCalls: 5 #最小请求个数,只有在滑动窗口内,请求个数达到这个个数,才会触发CircuitBreader对于断路器的判断 slidingWindowType: TIME_BASED #滑动窗口的类型 permittedNumberOfCallsInHalfOpenState: 3 #当CircuitBreaker处于HALF_OPEN状态的时候,允许通过的请求个数 automaticTransitionFromOpenToHalfOpenEnabled: true #设置true,表示自动从OPEN变成HALF_OPEN,即使没有请求过来 waitDurationInOpenState: 2s #从OPEN到HALF_OPEN状态需要等待的时间 recordExceptions: #异常名单 - java.lang.Exception instances: backendA: baseConfig: default
-
启动器
@SpringBootApplication @EnableDiscoveryClient public class GatewayServerApplication { public static void main(String[] args) { SpringApplication.run(GatewayServerApplication.class, args); } }
-
启动并测试
启动后访问http://localhost:9010,可以看到eureka管理界面中已经有gateway服务了:
启动后访问http://localhost:8086/api/bill/list,可以看到数据库查出的json格式数据:
3. 创建Config Server
-
在刚刚工程下再新建一个module,还是选择spring initializr
-
指定springboot版本,然后选择依赖:
Config Server
-
由于配置中心服务端需要借助消息队列,这里使用的是RabbitMQ,教程:MacBookPro(M1芯片)安装RabbitMQ
-
配置文件上传到了码云进行统一管理,结构如下
-
修改配置文件
server: port: 9011 spring: application: name: config-center rabbitmq: host: 127.0.0.1 port: 5672 # rabbitmq运行的默认端口号 username: guest password: guest cloud: config: server: git: uri: https://gitee.com/ellen0221/remote_application.git # 仓库地址 search-paths: config # 配置文件所在目录 default-label: master # 配置文件分支 # 如果是私有仓库则需要配置username和password username: xxx password: xxx # 暴露/actuator/bus-refresh端点 用于测试配置自动刷新 management: endpoints: web: exposure: include: bus-refresh endpoint: bus-refresh: enabled: true
-
启动器
@SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
-
启动并测试
启动后访问 http://localhost:9011/bill-service-dev.yml ,即可查看到对应配置文件的内容。
访问规则:/{application}-{profile}.yml
/{lable}/{application}-{profile}.yml
{application}:就是应用的名称,如bill-service
{profile}:就是配置文件的版本,有开发版本(dev)、测试环境版本(test)、生产环境版本(prod)
{label}:表示分支,默认是master
-
修改bill_service项目,实现远程获取配置及自动刷新:
-
修改配置文件
spring: application: name: bill-service rabbitmq: # 消息队列帮助实现自动刷新配置 host: 127.0.0.1 port: 5672 username: guest password: guest cloud: config: uri: http://localhost:9011 # 配置中心的地址 profile: dev # 配置文件的环境,最后会去http://localhost:9011/bill-service-dev.xml获取配置文件 label: master config: import: optional:configserver:http://localhost:9011 # 指定Spring Boot项目从Config Server导入配置
-
给Controller添加
@RefreshScope
注解,实现配置自动刷新
-
启动并测试
可以在controller中使用
@Value
注解获取配置文件中配置的值,并写一个接口进行测试@Value("${key}") private String key; /** * @desc 列表页面 * @Return: java.lang.String * @author: JingXu * @date: 3/5/22 8:03 PM */ @RequestMapping("/key") public void key() { System.out.println("remote application key: " + key); }
运行起来后访问 http://localhost:9001/key,可以获得配置的key值,在gitee修改该值,然后使用postman发起post请求,访问 http://localhost:9011/actuator/busrefresh,随后Spring Cloud Bus 会向RabbitMQ消息队列推送消息,bill-service监听到消息后,便重新获取配置文件,再次访问 http://localhost:9001/key,发现key值已经更新。
-