SpringCloud——微服务

目录

导入hmall单体项目

认识微服务

单体架构

微服务架构

SpringCloud

微服务拆分

熟悉代码

拆分原则

远程调用

服务治理

注册中心原理

Nacos注册中心

服务发现

OpenFeign

快速入门

连接池

最佳使用

日志

网关

网关路由

快速入门

路由属性

网关登录校验

思路及问题

自定义过滤器

GlobalFilter

GatewayFilter

登录校验代码

配置管理

问题提出

共享配置

配置热更新

动态路由


SpringCloud官网:https://spring.io/projects/spring-cloud

导入hmall单体项目

在Docker中我们已经部署了hmall项目,项目资源默认是用dev中的Mysql的配置,所以我们在上一篇文章Docker就能成功运行,但是我们想让他改成本地的local就要如下步骤

SpringCloud——微服务

SpringCloud——微服务SpringCloud——微服务

SpringCloud——微服务

认识微服务

单体架构

SpringCloud——微服务

微服务架构

SpringCloud——微服务

SpringCloud

SpringCloud——微服务

国内公司大多都用JDK8或者JDK11,2022.0.xSpringCloud对应的是3.0.x的SpringBoot版本底层必须JDK17以上,所以我们学习2021.0.x的SpringCloud版本。

SpringCloud——微服务

在pom.xml文件中我们有如下:

SpringCloud——微服务

Ctrl+B进入Spring-cloud-dependencies中可以看到里面有SpringCloud中的组件以及版本控制,几乎所有的SpringCloud的组件这里面都引入了。所以我们在引入了Spring-cloud-dependencies以后,我们在开发过程中就不需要指定组件的版本了,以后要用到那个版本,直接把组件引入过来,不用管版本。

微服务拆分

熟悉代码

ThreadLocal重点,在苍穹外卖中也讲过。

SpringCloud——微服务

SpringCloud——微服务

拆分原则

SpringCloud——微服务

SpringCloud——微服务

微服务项目结构

拆分的工程结构有两种:

SpringCloud——微服务

独立的project是指,地下每一个微服务(模块)就是一个project,而黑马商城hmall是一个空文件夹,文件夹里面就有这些所有的project。

Maven聚合是,如上图,黑马商城就是一个project,底下的每个微服务就都是一个模块。如下图,每新建一个模块其实就是新建一个微服务,这种模式看起来和单体架构差不多,但是其实有区别的,如下图单体架构hm-common他是不运行的,只有hm-service是运行的。(这种模式更加方便我们去管理,这种结构比较受中小型项目的一些欢迎,所以之后我会来讲这种模式)

SpringCloud——微服务

注意拆分的时候,配置里面的数据库的连接,数据库的连接很重要,每个微服务都要做到独立,独立部署,数据独立等,也就是说我们需要重新去创建一个新的Mysql的实例,利用Docker重新创建一个,这个微服务独享一台mysql,那么IP地址端口肯定都会变化,但是这样成本太高。所以我的建议是我们就搞一台Mysql,然后在里面创建不同的Database(数据库),一个微服务一个数据库,模拟一下,但是真实的企业中肯定是一个微服务一个独立的mysql实例。(如下图,配置修改了数据库的名称)

SpringCloud——微服务

远程调用

问题引入:

当我们把hmall项目的购物车以及商品两个微服务拆分时,购物车有的业务需要商品的查询功能,就需要调用商品的Service层的代码,但是现在他们两个是两个微服务,并且数据库也是不一样的,从物理上隔离开了,没办法去调用商品的Service层代码,所以我们在查询购物车的时候拿不到商品的信息。

解决:物理上两者是隔绝的,但是从网络上两者又是相通的,因为这两者之后部署到服务器上也好,部署到容器当中也好,都是可以通过网络连接的。所以可以通过网络请求数据。购物车微服务通过网络向商品微服务发起请求:

SpringCloud——微服务

购物车服务怎么向商品服务发网络请求呢?Java在这方面就模拟了前端向后端发送http请求,因为前端是个静态页面,需要后端传递数据才可以实现各种业务,如上的问题也可以模拟前端向后端发送的请求来完成。(针对于返回值类型,其实本来应该是JSON格式的数据,但是Java会反序列化成实体class类型给你)

SpringCloud——微服务

举例:

SpringCloud——微服务

restTemplate还存在很多问题需要改进,如下我会一一讲解。

服务治理

注册中心原理

问题引入:

如下图,在真正的实际开发当中,这个商品微服务可能压力会很大,我们会把一个服务部署多份,也就是说给他创建多个容器,同时去启动,同时去接收,那么这样就会形成一个负载均衡的集群了。那么这个时候去启动商品的微服务就有三个容器了,那么发请求的时候到底发给哪一个端口以及IP地址?这就涉及到了注册中心原理。

SpringCloud——微服务

解决:(负载均衡也有很多策略,比如轮询、随机、加权等,在nginx中说过)(心跳续约是指告诉注册中心自己能用,如果里面有某一个容器(实例)没有发心跳那就说明用不了了,注册中心就会把这个容器从服务列表中删除掉)

SpringCloud——微服务

Nacos注册中心

SpringCloud——微服务

通过Docker去部署nacos,部署之后去运行,之后输出日志(docker logs),然后在浏览器地址栏搜索框输入:虚拟机IP地址:8848/nacos就可以使用了。

现在假如要把item-service这个微服务加入注册中心,那么就要在它的pom.xml引入nacos的依赖,并且在.yml文件中配置nacos的地址。

SpringCloud——微服务

然后重新启动,在nacos注册中心就又对应的服务了

SpringCloud——微服务

模拟多个这样的微服务,也就是负载均衡都到注册中心:

SpringCloud——微服务SpringCloud——微服务

SpringCloud——微服务

然后启动,nacos注册中心:

SpringCloud——微服务

服务发现

购物车服务要去调用商品服务,不知道商品服务的地址,因此必须去nacos去拉取服务的信息,那么这个动作就是服务的发现。

SpringCloud——微服务

OpenFeign

快速入门

之前的代码很多,如下:(OpenFeign可以让这个代码变得简单)

SpringCloud——微服务

步骤:

SpringCloud——微服务

SpringCloud——微服务

连接池

SpringCloud——微服务

OpenFeign连接默认是HttpURLConnection不支持连接池,为了提高项目性能,所有远程调用的性能,我们就用支持连接池的,可以减少创建连接、销毁连接的开销。

SpringCloud——微服务

最佳使用

在之前我们只解决了购物车要调用商品微服务的Service接口的问题,如果说订单他也需要调用商品微服务的Service接口的根据id批量查询商品,那么和购物车微服务相同的步骤还要在做一遍。

方案一:(把这个代码写在商品微服务中,引入购物车和订单微服务的pom文件中)(项目结构变复杂了,一个微服务有拆分成三个模块,但是企业用的比较多)

SpringCloud——微服务

方案二:(在所有的要用到别的Service业务层代码的微服务都要在其pom文件中引入hm-api的依赖)(耦合度高)

SpringCloud——微服务

这里我用方案二,更简单。

遇到的问题:(当启动购物车微服务时,启动类扫描不到ItemClient接口,把它注入不到Sprig中去)

SpringCloud——微服务

日志

这个日志级别之前在.yml配置文件中声明了

SpringCloud——微服务

因为DefaultFeignConfig上面没有配置类的注解,所以Spring一开始不会把他注入。

SpringCloud——微服务

网关

问题:

当把项目拆分成各个微服务,购物车、用户、订单、支付。只有用户有登录的功能,其他服务都没有,那么登录用户的信息该如何获取?

每个微服务都有自己的端口,前端该访问哪一个?

解决:(网关其实也是一个微服务)

SpringCloud——微服务

前端只用知道网关的地址以及端口就行了,网关根据前端的请求去判断应该有哪个微服务去处理这个请求(请求的路由),判断出来之后网关就会把这个请求转发到对应的微服务(转发)(网关其实也可以看成一个微服务,然后它根据注册中心知道各个微服务的地址),假如前端请求的业务需要登录,而前端没有登录,那么就访问不了,如果登录了那么首先会解析JWT从而得到登录用户的信息,再把这个信息向后传递。

之后我会讲最主流的Spring Cloud Gateway。

SpringCloud——微服务

网关路由

快速入门

从注册中心拉取服务、负载均衡、发请求等等和业务功能无关,是网关可以自动做的事情。

而网关的路由,也就是判断前端的请求改由那个服务去处理,就跟业务有关。(配置这个网关的路由其实就是我们写网关代码的核心)

SpringCloud——微服务

路由属性

在yaml文件中所有的配置属性,最终都会有一个对应的Java类来读取,而网关路由对应的Java类型是RouteDefinition来读取。

之前的predicates路由断言是根据路径来找到对应的服务器,其实Spring给我们提供了很多的路由断言方式。

filters的作用不是去拦截谁,而是对于进入网关的前端请求,还有微服务处理完之后得到的响应结果去做一些加工和处理。Spring也给我们提供了好多种路由过滤器。

SpringCloud——微服务

路由断言:

SpringCloud——微服务

路由过滤器:

SpringCloud——微服务

网关登录校验

思路及问题

登录授权是在用户微服务,这个是没有问题的,因为不管在哪个微服务,只要登录完,就会给用户颁发一个Jwt的token,他就会带着token来访问网关,这时就可以从token中解析用户信息,所以登录授权可以不用变,就放在用户微服务就可以。但是对于Jwt的校验就不一样了,因为很多微服务都需要知道用户的信息,比如购物车微服务、交易微服务等等它都需要知道当前登录的用户是谁,要知道当前的用户就需要做Jwt的校验,难道我需要在所有的微服务都做Jwt的校验吗?

这个Jwt校验在网关里做,并且在网关把请求转发到微服务之前去做,网关把用户信息传递给微服务。

SpringCloud——微服务

Jwt校验如何放在网关把请求转发到微服务之前去做?如下图,我们可以把Jwt校验放到Filter过滤器的pre中。

SpringCloud——微服务

网关如何将用户信息传递给微服务?之前传递用户都用threadload,但是这里不行,因为网关是一个独立的微服务,并且用户、购物车等也都是一个独立的微服务,他们部署在不同的Tomcat上,而threadload是部署在Tomcat内部,线程之间共享,现在是不同的Tomcat所以不能共享。网关到微服务其实是一个新的Http请求,通过Http请求去传递信息,所以网关在校验完了之后,把用户扔到请求头,然后发请求到微服务,微服务也能从请求头中获取用户。

SpringCloud——微服务

微服务之间的Http请求是基于Openfeign发起的,而网关到微服务,是网关内部的一个Http请求发起方式,所以它们保存用户信息到请求头在实现方式上还是有点差别的。

如何在网关中自定义过滤器并且控制它的顺序?

如何在网关中编写登录校验的逻辑?

怎么把网关得到的用户传递给微服务?

用户信息在微服务之间怎么做传递?

自定义过滤器

SpringCloud——微服务

SpringCloud——微服务

GatewayFilter作用于指定路由是指:前面讲过的配置filter(如下图),在yaml文件中配置了filters的路由,或者default-filters表示每个路由器都有这个过滤器;而GlobalFilter是默认所有路由都生效。

SpringCloud——微服务

GlobalFilter

SpringCloud——微服务

GatewayFilter

这里不展示了,因为在企业开发中很少会用到,大部分用的都是GlobalFilter。

登录校验代码

代码开源到了gitee:https://gitee.com/git-shineyl/stop

如何在网关中编写登录校验的逻辑?

怎么把网关得到的用户传递给微服务?

如下图,传递给微服务,但是微服务里面也有很多的业务(Controller接口),它们可能都要获得用户,总不能都写一样的代码来完成,所以就用到了拦截器,把用户保存到ThreadLocal中,这样业务直接在ThreadLocal中获取信息就可以了。

SpringCloud——微服务

但是有很多微服务难道每个微服务里面都要写一遍拦截器吗?因此我们写在hm-common里面就可以了。

补充要用到的一个api的方法

SpringCloud——微服务

用户信息在微服务之间怎么做传递?

SpringCloud——微服务

这里清理购物车,是根据订单id以及用户id来删除的,可以看看源代码(也可以不看,听我描述),订单在保存订单的时候只传递了订单id,而购物车只收到了订单id,它的用户id是通过UserContext.getUser()来获得的,经过测试发现获取不到,为什么呢?因为这个请求他不是通过网关发过来的,是通过交易微服务发过来的,所以获取不到用户id,也就清理不了购物车。

从交易微服务到购物车微服务,发送请求是CartClient接口来调用的,也就是OpenFeign发送的请求:

SpringCloud——微服务

配置管理

问题提出

如下图:(简单来说就是网关以及各个微服务里面的yaml配置文件有很多都是重复的,比如mybatis的配置等等,如果要改动一个配置,那么所有的都要改,这样不方便管理;所以把他们交给配置管理服务去管理,配置共享)(还有一个就是配置变更,需要重启也很麻烦,配置管理服务可以去监听配置变更,配置变更会推送到对应的微服务,这样就可以不用重启)

SpringCloud——微服务

nacos不仅有注册中心的功能,还有配置管理服务的功能。

共享配置

一、添加配置到Nacos

步骤:

SpringCloud——微服务

SpringCloud——微服务

其他共享配置类似:

SpringCloud——微服务

二、拉取共享配置

微服务拉取配置的底层流程:(因为Nacos的地址配置在application.yaml中,所以如果启动要先拉取Nacos配置,就可以再创建一个bootstrap.yml文件,把Nacos地址从application.yaml转到bootstrap.yml就可以了)

SpringCloud——微服务

步骤:

SpringCloud——微服务

SpringCloud——微服务

配置热更新

SpringCloud——微服务

实现购物车添加商品上限的配置热更新:

之前是在service的impl中硬编码,使它的购物车数量不超过10:

SpringCloud——微服务

在购物车微服务中添加如上图步骤的配置类:

SpringCloud——微服务SpringCloud——微服务

data-Id可以不指定Spring.active.profile(local或者dev),直接如下图指定,这样不管是local还是dev都可以生效

SpringCloud——微服务

动态路由

代码开源到gitee,可以看代码:https://gitee.com/git-shineyl/stop

问题:

我之前说的在gateway网关微服务配置的路由是静态的,写死在网关的微服务中,当网关微服务启动的时候就会加载配置文件当中的路由信息,然后把他保存在内存当中,一个路由表里面,其实就是一个缓存。那么这样以后再处理请求判断路由的时候,它就不用再去读文件了,直接读缓存就可以了。但是会面临一个问题:假如说项目在运行过程中,我们的路由信息需要发生变更,那么这时只去该配置文件是不对的,因为他已经缓存起来了,所以必须要重启网关服务才行,但是网关是整个微服务的入口,他不能随便停机。所以我们希望当路由变更的时候,一修改他立马能生效,不用重启网关。

Nacos的配置管理这一方面的解释:https://nacos.io/zh-cn/docs/sdk.html

SpringCloud——微服务

SpringCloud——微服务

SpringCloud——微服务

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...