简介
微服务-注册中心、配置中心、网关
API网关->注册中心、配置中心:商品服务、优惠服务、仓储服务、订单服务、支付服务、用户服务、秒杀服务、检索服务、购物车服务。。。。
1.SpringCloud Alibaba简介
SpringCloud Alibaba致力提供微服务开发的一站式解决方案,开发分布式应用微服务的必需组件。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
2.SpringCloud 技术搭配方案
- SpringCloud Alibaba-Nacos:注册中心(服务发现/注册)
- SpringCloud Alibaba-Nacos:配置中心(动态配置管理)
- SpringCloud -Ribbon:负载均衡
- SpringCloud-Feign:声明式Http客户端
- SpringCloud Alibaba-Sentinel:服务容错(限流、降级、熔断)
- SpringCloud-Gateway:Api网关(webflux 编程模式)
- SpringCloud-Sleuth:调用链监控
- SpringCloud Alibaba -Seate : 原Fescar 即分布式事务解决方案
在common的pom.xml中加入
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
上面是依赖管理,相当于以后再dependencies里引spring cloud alibaba就不用写版本号, 全用dependencyManagement进行管理
Naocs 作为注册中心
一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
作为我们的注册中心和配置中心。
注册中心文档:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md
首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
@SpringBootApplication @EnableDiscoveryClient public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } @RestController class EchoController { @GetMapping(value = "/echo/{string}") public String echo(@PathVariable String string) { return string; } } }
启动 Nacos Server
- 首先需要获取 Nacos Server,支持直接下载和源码构建两种方式。
- 直接下载:Nacos Server 下载页
- 源码构建:进入 Nacos Github 项目页面,将代码 git clone 到本地自行编译打包,参考此文档。推荐使用源码构建方式以获取最新版本
- 启动 Server,进入解压后文件夹或编译打包好的文件夹,找到如下相对文件夹 nacos/bin,并对照操作系统实际情况之下如下命令。
- Linux/Unix/Mac 操作系统,执行命令
sh startup.sh -m standalone
- Windows 操作系统,执行命令
cmd startup.cmd
应用启动
增加配置,在 nacos-discovery-provider-example 项目的 /src/main/resources/application.properties 中添加基本配置信息
spring.application.name=service-provider server.port=18082
启动应用,支持 IDE 直接启动和编译打包后启动。
- IDE直接启动:找到 nacos-discovery-provider-example 项目的主类
ProviderApplication
,执行 main 方法启动应用。- 打包编译后启动:在 nacos-discovery-provider-example 项目中执行
mvn clean package
将工程编译打包,然后执行java -jar nacos-discovery-provider-example.jar
启动应用。验证
查询服务
http://127.0.0.1:8848/nacos
Feign声明式远程调用
-
测试案例
member和coupon的远程调用
想要获取会员领取到的所有优惠券。先去注册中心找优惠券服务,注册中心调用一台优惠券服务器给会员,会员服务器发送请求给这台优惠卷服务器,然后对方响应。
Feign 声明式远程调用 目的是让远程调用更加简单。给远程服务器发的是Http请求
会员服务想要远程调用优惠券服务,需要给会员服务里引用openfeign 依赖,他就有了远程调用其他服务的能力。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
在coupon 优惠券服务中添加如下内容
@RequestMapping("/member/list") public R membercoupons(){ // // 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回 CouponEntity couponEntity = new CouponEntity(); couponEntity.setCouponName("满一百减10");//优惠券的名字 return R.ok().put("coupons",Arrays.asList(couponEntity)); }
-
在memeber的配置类上加注解@EnableDiscoveryClient ,告诉member是一个远程调用客户端,member要调用东西的
/* * 想要远程调用的步骤: * 1 引入openfeign * 2 编写一个接口,接口告诉springcloud这个接口需要调用远程服务 * 2.1 在接口里声明@FeignClient("gulimall-coupon")他是一个远程调用客户端且要调用coupon服务 * 2.2 要调用coupon服务的/coupon/coupon/member/list方法 * 3 开启远程调用功能 @EnableFeignClients,要指定远程调用功能放的基础包 * */ @EnableFeignClients(basePackages="com.atguigu.gulimall.member.feign") @EnableDiscoveryClient @SpringBootApplication public class gulimallMemberApplication { public static void main(String[] args) { SpringApplication.run(gulimallMemberApplication.class, args); } }
-
调用的在member的com.atguigu.gulimall.member.feign包下接口类:
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") //告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法 public interface CouponFeignService { @RequestMapping("/coupon/coupon/member/list")//注意写全优惠券类上还有映射//注意我们这个地方不熟控制层,所以这个请求映射请求的不是我们服务器上的东西,而是nacos注册中心的 public R membercoupons();//得到一个R对象 }
-
在member的控制层写一个测试请求
@RestController @RequestMapping("member/member") public class MemberController { @Autowired private MemberService memberService; @Autowired CouponFeignService couponFeignService; @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")); }
-
重启服务测试http://localhost:8000/member/member/coupons
Nacos 作为配置中心
-
配置中心依赖 在common
# 配置中心来配置管理 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 元数据
spring.application.name=nacos-config-example // 当前应用的名字 spring.cloud.nacos.config.server-addr=127.0.0.1:8848 // 配置中心的地址
-
需要给配置中心默认添加一个叫gulimall-coupon.properties 一个叫数据集(Data Id) 默认规则 应用名.properties
-
给应用名.properties 添加任何配置
-
动态获取配置。
-
@RefreshScope# 动态获取并刷新配置 @Value("${配置项的名}"); 获取到配置 如果配置中心和当前应用的配置文件中都有相同的配置,优先使用配置中心的配置
引入配置中心依赖,放到common中
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> 1234
在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是springboot里规定的,他优先级别application.properties高
# 改名字,对应nacos里的配置文件名 spring.application.name=gulimall-coupon spring.cloud.nacos.config.server-addr=127.0.0.1:8848
-
原来的方式:
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写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);
}
浏览器去nacos里的配置列表,点击+号,data ID:gulimall-coupon.properties
,配置
# gulimall-coupon.properties
coupon.user.name="配置中心"
coupon.user.age=12
然后点击发布。重启coupon,http://localhost:7000/coupon/coupon/test
{"msg":"success","code":0,"name":"配置中心","age":12}
实际生产中不能重启应用。在coupon的控制层上加@RefreshScope
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写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);
}
重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了
nacos的配置内容优先于项目本地的配置内容。
引入配置中心依赖,放到common中
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是springboot里规定的,他优先级别application.properties高
# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
原来的方式:
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写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);
}
浏览器去nacos里的配置列表,点击+号,data ID:gulimall-coupon.properties
,配置
# gulimall-coupon.properties
coupon.user.name="配置中心"
coupon.user.age=12
然后点击发布。重启coupon,http://localhost:7000/coupon/coupon/test
{"msg":"success","code":0,"name":"配置中心","age":12}
实际生产中不能重启应用。在coupon的控制层上加@RefreshScope
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写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);
}
重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了
-
配置中心进阶
- 命名空间:配置隔离
默认:public(保留空间);默认新增的所有配置都在public空间。
-
开发,测试,生产:利用命名空间做环境隔离
- 在bootstrap.propertirs 配置上,需要使用那个命名空间下的配置。
spring.cloud.nacos.config.namespace=90e95214-105d-4a78-bffe-86b014edb077 #命名空间的唯一Id
- 每一微服务之间互相隔离配置,每一个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置
-
配置集
所有配置的集合
-
配置集ID
类型配置文件名 Data ID :类似文件名
-
配置分组
默认所有的配置集都属于:DEFAULT_GROUP
# 更改配置分组 spring.cloud.nacos.config.group=DEFAULT_GROUP
-
每一个微服务创建自己的命名空间,使用配置分组区分环境,dev 、test、prod
-
同时加载多个配置集
我们要把原来application.yml里的内容都分文件抽离出去。我们在nacos里创建好后,在coupons里指定要导入的配置即可。
SpringCloud-Gateway:Api网关
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uugHezLa-1599220061617)(C:\Users\Administrator\Desktop\SpringBoot学习\项目笔记\images\SpringCloudGateway.png)]
发送请求需要知道商品服务的地址,如果商品服务器有123服务器,1号掉线后,还得改,所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上线还是下线。
请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。
所以我们使用spring cloud的gateway组件做网关功能。
网关是请求浏览的入口,常用功能包括路由转发,权限校验,限流控制等。springcloud gateway取到了zuul网关。
三个核心概念:
-
Route
-
Predicate
-
Filter
官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.5.RELEASE/single/spring-cloud-gateway.html#_addrequestheader_gatewayfilter_factory
案例:创建,使用initilizer,Group:com.atguigu.gulimall,Artifact: gulimall-gateway,package:com.atguigu.gulimall.gateway。 搜索gateway选中。
pom.xml里加上common依赖, 修改jdk版本,
开启注册服务发现@EnableDiscoveryClient
配置nacos注册中心地址applicaion.properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
server.port=88
bootstrap.properties 填写配置中心地址
spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=bfa85f10-1a9a-460c-a7dc-efa961b45cc1
1234
nacos里创建命名空间gateway,然后在命名空间里创建文件guilmall-gateway.yml
spring:
application:
name: gulimall-gateway
在项目里创建application.yml
spring:
cloud:
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu
- id: qq_route
uri: https://www.qq.com
predicates:
- Query=url,qq
## 前端项目,/api
测试 localhost:8080/hello?url=baidu