目录
- 一、前言
- 二、Spring Cloud&Spring Cloud Alibaba
- 1、Spring Cloud 与Spring Cloud Alibaba简介
- 2、为什么使用Spring Cloud Alibaba
- 3、版本选择
- 4、项目中的依赖
- 三、Spring Cloud Alibaba-Nacos作为注册中心
- 1、Nacos
- 1)、下载 nacos-server
- 2)、启动 nacos-server
- 3)、将微服务注册到 nacos 中
- 1、首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。
- 2、在应用的 /src/main/resources/application.yml 配置文
- 3、使用@EnableDiscoveryClient 开启服务注册发现功能
- 4、启动应用,观察 nacos 服务列表是否已经注册上服务
- 5、每一个服务都配置好注册中心的配置,并验证,不然后续有问题排查比较难找
- 四、Spring Cloud Feign
- 1、简介
- 2、使用
- 1、引入依赖
- 2、开启 feign 功能,并声明远程调用的接口在哪个包下
- 3、声明远程接口
- 4、在member测试一下远程调用
- 5、启动member报错,因为引入了多个版本的spring-boot
- 6、远程调用执行流程
- 1、在coupon写正常的接口
- 2、在member要远程调用其他服务的controller添加@EnableFeignClients(basePackages = "com.wxn.zhenyanmall.member.feign")
- 3、创建远程调用的接口
- 4、在member中调用coupon的接口
- 五、Spring Cloud Alibaba Nacos作为配置中心
- 1、pom.xml 引入 Nacos Config Starter。
- 2、在应用的 /src/main/resources/bootstrap.properties 配
- 3、在 nacos 中添加配置
- 4、在应用中使用@Value 和@RefreshScope
- 5、进阶
- 6、总结
- 六、Spring Cloud Gateway
- 1、简介
- 2、核心概念
- 3、使用
- 1、创建网关项目,引入网关
- 3、注意
- 4、测试
- 4、断言(Predicates)
- 5、过滤器(filters)
- 1、GatewayFilter
- 2、GlobalFilter
- 6、项目引入网关
- 1、创建网关module,引入gateway
- 2、添加common依赖
- 3、添加到注册中心和配置中心
- 4、在application.yml中添加网关配置,测试一下
- 5、然后在页面请求:http://localhost:88/?url=baidu
一、前言
搭建分布式的基本环境,主要是注册中心、配置中心、网关。
在分布式开发中,每一个微服务上线都应该将自己注册到注册中心,这样做的好处就是订单服务想要调用商品服务,可以去注册中心看一下,哪几个商品服务注册进来了,1号、2号,可以挑一个可用的商品服务去远程调用。
各个微服务的配置众多,当一个商品服务部署在十台机器上,改一个配置则需要改十次,如果放到配置中心,只需要改一次即可,集中管理配置。
所有的前端请求,都先通过网关,鉴权、过滤、路由等等,由网关请求对应的服务。
二、Spring Cloud&Spring Cloud Alibaba
1、Spring Cloud 与Spring Cloud Alibaba简介
https://spring.io/projects/spring-cloud
以前的Spring Cloud使用Spring Cloud Netfix种的Eureka作为注册中心,Spring Cloud Config作为配置中心,Spring Cloud Zuul作为网关,Hystrix作为断路保护。
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
https://github.com/alibaba/spring-cloud-alibaba
2、为什么使用Spring Cloud Alibaba
SpringCloud 的几大痛点
SpringCloud 部分组件停止维护和更新,给开发带来不便;
SpringCloud 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制
SpringCloud 配置复杂,难以上手,部分配置差别难以区分和合理应用
SpringCloud Alibaba 的优势:
阿里使用过的组件经历了考验,性能强悍,设计合理,现在开源出来大家用
成套的产品搭配完善的可视化界面给开发运维带来极大的便利
搭建简单,学习曲线低
结合 SpringCloud Alibaba 我们最终的技术搭配方案:
SpringCloud Alibaba - Nacos:注册中心(服务发现/注册)
SpringCloud Alibaba - Nacos:配置中心(动态配置管理)
SpringCloud - Ribbon:负载均衡
SpringCloud - Feign:声明式 HTTP 客户端(调用远程服务)
SpringCloud Alibaba - Sentinel:服务容错(限流、降级、熔断)
SpringCloud - Gateway:API 网关(webflux 编程模式)
SpringCloud - Sleuth:调用链监控
SpringCloud Alibaba - Seata:原 Fescar,即分布式事务解决方案
3、版本选择
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且
spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟
SpringBoot 版本号一致的版本:
1.5.x 版本适用于 Spring Boot 1.5.x
2.0.x 版本适用于 Spring Boot 2.0.x
2.1.x 版本适用于 Spring Boot 2.1.x
4、项目中的依赖
在 common 项目中引入如下。进行统一管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
三、Spring Cloud Alibaba-Nacos作为注册中心
1、Nacos
是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理
平台。他是使用 java 编写。需要依赖 java 环境
Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html
1)、下载 nacos-server
https://github.com/alibaba/nacos/releases
2)、启动 nacos-server
双击 bin 中的 startup.cmd 文件
访问 http://localhost:8848/nacos/
使用默认的 nacos/nacos 进行登录
3)、将微服务注册到 nacos 中
1、首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2、在应用的 /src/main/resources/application.yml 配置文
件中配置 Nacos Server 地址
3、使用@EnableDiscoveryClient 开启服务注册发现功能
4、启动应用,观察 nacos 服务列表是否已经注册上服务
5、每一个服务都配置好注册中心的配置,并验证,不然后续有问题排查比较难找
四、Spring Cloud Feign
1、简介
Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了 HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。
Feign 整合了 Ribbon(负载均衡)和 Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。
SpringCloudFeign 在 NetflixFeign 的基础上扩展了对 SpringMVC 注解的支持,在其实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了SpringCloudRibbon 自行封装服务调用客户端的开发量。
2、使用
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、开启 feign 功能,并声明远程调用的接口在哪个包下
@EnableFeignClients(basePackages = “com.wxn.zhenyanmall.member.feign”)
3、声明远程接口
/*
- 告诉SpringCloud这个接口是一个远程客户端
- 调用远程哪个服务coupon
- 这个远程服务有很多功能,到底调用哪个功能
- 只需要将要调用的接口服务名,完整的复制过来,然后修改一下路径加上/coupon/coupon/
*如果我们在这个服务里面调用 CouponFeignService接口的membercoupons方法, - 则会先去注册中心找远程服务coupon所在的位置,然后再去调用/coupon/coupon/member/list请求,对应的方法membercoupons
- 这样就实现了远程调用
- */
@FeignClient(“coupon”)
4、在member测试一下远程调用
5、启动member报错,因为引入了多个版本的spring-boot
6、远程调用执行流程
1、在coupon写正常的接口
2、在member要远程调用其他服务的controller添加@EnableFeignClients(basePackages = “com.wxn.zhenyanmall.member.feign”)
3、创建远程调用的接口
4、在member中调用coupon的接口
五、Spring Cloud Alibaba Nacos作为配置中心
https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md
bootstrap.properties 优先于application.properties加载
1、pom.xml 引入 Nacos Config Starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2、在应用的 /src/main/resources/bootstrap.properties 配
置文件中配置 Nacos Config 元数据
spring.application.name=coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
主要配置应用名和配置中心地址
如果配置中心有coupon.properties这个配置,会读取里面的配置,配置名一般是应用名+properties
3、在 nacos 中添加配置
在 nacos 中创建一个 应用名.properties 配置文件并编写配置
Nacos Config 数据结构
Nacos Config主要通过dataId和group 来唯一确定一条配置
Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 ConfigService.getConfig(String dataId, String group, long timeoutMs)。
Spring Cloud 应用获取数据
dataID:在 Nacos Config Starter 中,dataId 的拼接格式如下
${prefix} - ${spring.profiles.active} . f i l e − e x t e n s i o n p r e f i x 默认为 s p r i n g . a p p l i c a t i o n . n a m e 的值,也可以通过配置项 s p r i n g . c l o u d . n a c o s . c o n f i g . p r e f i x 来配置。 s p r i n g . p r o f i l e s . a c t i v e 即为当前环境对应的 p r o f i l e 注意,当 a c t i v e p r o f i l e 为空时,对应的连接符 − 也将不存在, d a t a I d 的拼接格式变成 {file-extension} prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置。 spring.profiles.active 即为当前环境对应的 profile 注意,当 activeprofile 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 file−extensionprefix默认为spring.application.name的值,也可以通过配置项spring.cloud.nacos.config.prefix来配置。spring.profiles.active即为当前环境对应的profile注意,当activeprofile为空时,对应的连接符−也将不存在,dataId的拼接格式变成{prefix}.${file-extension}
file-extension 为配置内容的数据格式,可以通过配置项
spring.cloud.nacos.config.file-extension 来配置。 目前只支持 properties 类型。
Group:
Group 默认为 DEFAULT_GROUP,可以通过 spring.cloud.nacos.config.group 配置。
4、在应用中使用@Value 和@RefreshScope
完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment的 PropertySources 中 。 这 里 我 们 使 用 @Value 注 解 来 将 对 应 的 配 置 注 入 到
SampleController 的 userName 和 age 字段,并添加 @RefreshScope 打开动态刷新功能
@RefreshScope
class SampleController {
@Value(“ u s e r . n a m e " ) S t r i n g u s e r N a m e ; @ V a l u e ( " {user.name}") String userName; @Value(" user.name")StringuserName;@Value("{user.age}”)
int age;
}
5、进阶
1、核心概念
命名空间:
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
配置集:
一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项
配置集 ID:
Nacos 中的某个配置集的 ID。配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。
配置分组:
Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如database_url 配置和MQ_topic 配置。
2、原理
自动注入:
NacosConfigStarter 实现了 org.springframework.cloud.bootstrap.config.PropertySourceLocator
接口,并将优先级设置成了最高。
在 Spring Cloud 应用启动阶段,会主动从 Nacos Server 端获取对应的数据,并将获取到的
数据转换成 PropertySource 且注入到 Environment 的 PropertySources 属性中,所以使用
@Value 注解也能直接获取 Nacos Server 端配置的内容。
动态刷新:
Nacos Config Starter 默认为所有获取数据成功的 Nacos 的配置项添加了监听功能,在监听
到服务端配置发生变化时会实时触发
org.springframework.cloud.context.refresh.ContextRefresher 的 refresh 方法 。
如果需要对 Bean 进行动态刷新,请参照 Spring 和 Spring Cloud 规范。推荐给类添加
@RefreshScope 或 @ConfigurationProperties 注解,
3、加载多配置文件
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=31098de9-fa28-41c9-b0bd-c754ce319ed4
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].refresh=false
spring.cloud.nacos.config.ext-config[0].group=dev.
4、namespace 与 group 最佳实践
每个微服务创建自己的 namespace 进行隔离,group 来区分 dev,beta,prod 等环境
6、总结
/**
- 1、如何使用Nacos作为配置中心统一管理配置
- 1)、引入依赖,
-
<dependency>
-
<groupId>com.alibaba.cloud</groupId>
-
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
-
</dependency>
- 2)、创建一个bootstrap.properties。
-
spring.application.name=gulimall-coupon
-
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
- 3)、需要给配置中心默认添加一个叫 数据集(Data Id)gulimall-coupon.properties。默认规则,应用名.properties
- 4)、给 应用名.properties 添加任何配置
- 5)、动态获取配置。
-
@RefreshScope:动态获取并刷新配置
-
@Value("${配置项的名}"):获取到配置。
-
如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置。
- 2、细节
- 1)、命名空间:配置隔离;
-
默认:public(保留空间);默认新增的所有配置都在public空间。
-
1、开发,测试,生产:利用命名空间来做环境隔离。
-
注意:在bootstrap.properties;配置上,需要使用哪个命名空间下的配置,
-
spring.cloud.nacos.config.namespace=9de62e44-cd2a-4a82-bf5c-95878bd5e871
-
2、每一个微服务之间互相隔离配置,每一个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置
- 2)、配置集:所有的配置的集合
- 3)、配置集ID:类似文件名。
-
Data ID:类似文件名
- 4)、配置分组:
-
默认所有的配置集都属于:DEFAULT_GROUP;
-
1111,618,1212
- 项目中的使用:每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prod
- 3、同时加载多个配置集
- 1)、微服务任何配置信息,任何配置文件都可以放在配置中心中
- 2)、只需要在bootstrap.properties说明加载配置中心中哪些配置文件即可
- 3)、@Value,@ConfigurationProperties。。。
- 以前SpringBoot任何方法从配置文件中获取值,都能使用。
- 配置中心有的优先使用配置中心中的,如果没有则使用配置文件
*/
六、Spring Cloud Gateway
1、简介
网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而 springcloud gateway作为 SpringCloud 官方推出的第二代网关框架,取代了 Zuul 网关。
网关提供 API 全托管服务,丰富的 API 管理功能,辅助企业管理大规模的 API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等功能。
Spring Cloud Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,并为他们提供切面,例如:安全性,监控/指标 和弹性等。
官方文档地址:
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html
Spring Cloud Gateway 特点:
基于 Spring5,支持响应式编程和 SpringBoot2.0
支持使用任何请求属性进行路由匹配
特定于路由的断言和过滤器
集成 Hystrix 进行断路保护
集成服务发现功能
易于编写 Predicates 和 Filters
支持请求速率限制
支持路径重写
为什么使用 API 网关?
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
客户端会多次请求不同的微服务,增加了客户端的复杂性。
存在跨域请求,在一定场景下处理相对复杂。
认证复杂,每个服务都需要独立认证。
难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性:
使用 API 网关后的优点如下:
易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
减少了客户端与各个微服务之间的交互次数。
2、核心概念
路由。路由是网关最基础的部分,路由信息有一个 ID、一个目的 URL、一组断言和一组Filter 组成。如果断言路由为真,则说明请求的 URL 和配置匹配
断言。Java8 中的断言函数。Spring Cloud Gateway 中的断言函数输入类型是 Spring5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 中的断言函数允许开发者去定义匹配来自于 http request 中的任何信息,比如请求头和参数等。
过滤器。一个标准的 Spring webFilter。Spring cloud gateway 中的 filter 分为两种类型的Filter,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 将会对请求和响应进行修改处理
工作原理:
客户端发送请求给网关,弯管 HandlerMapping 判断是否请求满足某个路由,满足就发给网关的 WebHandler。这个 WebHandler 将请求交给一个过滤器链,请求到达目标服务之前,会执行所有过滤器的 pre 方法。请求到达目标服务处理之后再依次执行所有过滤器的 post 方法
满足某些断言(条件)(predicates)就路由到指定的地址(uri),使用指定的过滤器(filter)
3、使用
1、创建网关项目,引入网关
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
### 2、编写网关配置文件
spring:
cloud:
gateway:
routes: - id: add_request_parameter_route
uri: https://example.org
predicates: - Query=baz
filters: - AddRequestParameter=foo, bar
3、注意
各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
一个请求满足多个路由的谓词条件时,请求只会被首个成功匹配的路由转发
4、测试
可以使用 postman 进行测试网关的路由功能
4、断言(Predicates)
5、过滤器(filters)
1、GatewayFilter
2、GlobalFilter
6、项目引入网关
1、创建网关module,引入gateway
2、添加common依赖
3、添加到注册中心和配置中心
4、在application.yml中添加网关配置,测试一下
因为网关引用公共模块common中引入了数据源驱动,而配置文件中不需配置数据源,导致报错,只需要在启动类加上@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 即可,去除DataSourceAutoConfiguration.class
然后就能启动成功了。
5、然后在页面请求:http://localhost:88/?url=baidu
如果请求的是:http://localhost:88/hello?url=qq
网关实际请求的是:https://www.qq.com/hello 就会报页面不存在