目录
- 2. http客户端Feign
- 2.1 Feign替代RestTemplate
- 2.1.1 RestTmmplate方法调用存在的问题
- 2.1.2. Feign的介绍
- 2.1.3. Feign的使用
- 2.2 自定义配置
- 2.3 Feign使用优化
- 2.3.1 优化的底层原理
- 2.3.2 优化的方向
- 2.3.3 连接池配置
- 2.4 最佳实践
- 2.4.1 方式一:继承
- 2.4.2 方式二:抽取
- 3. 统一网关Gateway
- 3.1 为什么需要网关
- 3.2 GateWay的快速入门
- 3.3 断言工厂
- 3.4 过滤器工厂
- 3.5 全局过滤器(GlobalFilter)
- 3.5.1 什么是全局过滤器,为什么需要全局过滤器
- 3.5.2. 全局过滤器的实现方式
- 3.5.3. 全局过滤器的实现案例
- 3.5 过滤器的执行顺序
- 3.6 限流过滤器
- 3.7 小总结
- 图片:
- 红色字体
2. http客户端Feign
Feign是一种新的使用http进行远程调用的方式。
2.1 Feign替代RestTemplate
2.1.1 RestTmmplate方法调用存在的问题
1)使用方法:在启动类书写一个方法,然后通过url在service中进行调用
String url = "http://userservice/user/" + order.getUserId();User user = restTemplate.getForObject(url, User.class);
- 代码可读性太差,需要固定输入一个URL,不够灵活
- 当参数变得复杂的时候,URL难以维护。
2.1.2. Feign的介绍
1)是一种申明式的http客户端,作用是帮助我们优雅实现http请求的发送,解决上面提到的问题。
2) 实现逻辑还是差不多的,都是为了生成一个url进行远程调用。只不过在Feign中,采用申明式结构进行URL的拆分再组装。
2.1.3. Feign的使用
- 在order-service的pom文件中引入依赖:spring-cloud-starter-openfeign
<dependency><groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
- 在orderservice的启动类中添加注解,开启Feign的功能:@EnableFeignClients
- 在Feign-api项目中编写Feign的客户端(Feign-client)
为了相对应,需要和user中的controller中的类保持参数的一直性
@FeignClient("userservice")public interface UserClient {@GetMapping("/user/{id}") User findById(@PathVariable("id") Long id);}
上述定义Feign客户端中,包含很多信息:
(1)服务名称:userservice
(2)请求方式:Get
(3)请求路径:/user/{id}
(4)请求参数:Long id
(5)返回对象:User
- 用Feign客户端代替RestTemplate
第二行红色,两行给为一行了!
String url="http://localhost:8081/user/"+order.getUserId();//获取用户的id信息User user=restTemplate.getForObject(url,User.class); //通过url进行远程调用,并把得到的数据变为user格式
- 小结
1)引入依赖
2)启动类添加注解@EnableFeignClients
3)编写FeignClient接口
4)使用FeignClient中定义的方法替代RestTemplate
2.2 自定义配置
一般使用比较多的是:日志级别的修改,共有四种级别:NONE,BASIC,HEADERS,FULL,一般默认选用NONE即可
2.3 Feign使用优化
2.3.1 优化的底层原理
主要是在Feign底层进行优化,即采用具有连接池的原理。
Feign底层的客户端实现:
1)URLConnection:默认实现,不支持连接池(性能一般)
2)Apache HttpClient:支持连接池(不用每次都请求链接,效率更高)
3)OKHttp:支持连接池
2.3.2 优化的方向
优化的方向:
1)使用连接池代替默认的URLConnection
2)日志级别的修改:使用NONE和BASIC,更加简洁。
2.3.3 连接池配置
Feign添加HttpClient的支持,故需要引入依赖和配置连接池
- 在Feign-api中引入依赖
<!--feign-api的依赖 --><dependency> <groupId>cn.itcast.demo</groupId> <artifactId>feign-api</artifactId> <version>1.0</version></dependency>
- 配置连接池(同时修改日志级别)
feign:client:config:default: # default全局的配置loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息 httpclient: enabled: true # 开启feign对HttpClient的支持 max-connections: 200 # 最大的连接数 max-connections-per-route: 50 # 每个路径的最大连接数
2.4 最佳实践
2.4.1 方式一:继承
- 方式:从 2.1.3. Feign的使用中可知,Feign客户端的编写与user服务service的编写很像,故可以抽象出相同部分,然后给这两个地方继承。
- 缺点:1)两个服务会产生紧耦合,并且父接口参数列表中的映射并不会被继承。
2.4.2 方式二:抽取
- 方法:将FeignClient抽取为独立的模块,并把与接口与欧冠的POJO,默认的Feign配置都放到这个模块中来,提供给所有的消费者使用。(其他消费者只需要在启动类中添加注解@EnableFeignClients即可使用)
注意事项:由于是新建的一个项目Feign-api,故其他服务在使用过程中需要引入依赖才能使用其他项目的服务。
<!--引入feign的统一api--><dependency><groupId>cn.itcast.demo</groupId><artifactId>feign-api</artifactId><version>1.0</version></dependency>
- 抽取FeignClient的步骤
1)创建mudule并依赖首先创建一个module,取名为feign-api,然后引入feign的starter依赖
2)将order中编写的UserLcient,User,DefaultFeignConfiguration都复制到feign-api项目中
3)在order-service引入feign-api的依赖
4)修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api的包
5)重启测试 - FeignClient不在启动类扫描包饭内内解决方法
1)指定FeignClient所在包(范围大,全导进来了)
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
2)指定FeignClient字节码(小范围)
@EnableFeignClients(clients = {UserClient.class})
3. 统一网关Gateway
3.1 为什么需要网关
1. 网关的作用
1)身份认证和权限校验等:不是什么用户通过链接都能够访问的,需要指定的用户名等情况,或者需要某一些权限处于开启状态;
2)服务路由和负载均衡:将用户请求路由到微服务,并实现负载均衡。网关具有负载均衡的作用,故不需要自己去配置Ribbon
3)请求限流:同一个时刻,对于服务的访问,限制流量,不能够过于频繁访问。
2. 网关技术的实现
目前SpringCloud中,网关的实现包括两种:
1)gateway:SpringCloudGateWay则属于Spring5中提供的WebFlux,属于响应式编程的实现,具有更好的性能。
2)zuul:基于Servlet的实现,属于阻塞式的编程
3)区别:响应式编程和阻塞式编程。
3.2 GateWay的快速入门
- 建module,引依赖:网关依赖和服务发现依赖
<!--网关依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--nacos服务发现依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
- 配置文件:编写路由配置和nacos的地址(编码形式设置网关)
根据上面可知,网关路由route的配置包含以下四个部分:
1) 路由id:路由的id,是路由的唯一表示
2)路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
3)路由断言(predicates):判断路由的规则,例如Path=/user/**,判断路径是否以/user开头,如果是则符合
4)路由过滤器(filters):对请求和相应做处理
- 网关的执行过程
3.3 断言工厂
上述配置中的断言都是通过断言工厂进行执行的:读取用户定义的断言条件,对请求做出判断
1)我们在配置文件中书写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
2)例如Path=/user/**是按照路径匹配,规则是org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类处理的
3)像这样的断言工厂还有好几十个,可自行通过说明进行使用。
3.4 过滤器工厂
1. 过滤器工厂介绍
在路由确定之后会通过过滤器进行过滤操作,再通过负载均衡分配到具体的服务中去。
过滤器可以对进入网关的请求和微服务返回的响应做处理
2. 过滤器工厂种类
Spring提供了31种不同的路由过滤器工厂
3. 过滤器工厂使用案例
1)要求:给所有进入userservice的请求,添加一个请求头:Truth=itcast is freaking awesome!
2)实现步骤
(1)在gateway中修改配置文件,给userservice的路由添加过滤器
spring:cloud: gateway:routes: # 网关路由配置- id: user-service #路由iduri: lb://userservice#路由路径predicates:#路由断言- Path=/user/‘**’#判断是否存在/user路径 filters: # 过滤器,带有s,可以有多个操作 - AddRequestHeader=Truth, Itcast is freaking awesome!# 添加请求头
(2)如果要对所有的路由都生效,故需要将过滤器工厂写到default下面,格式如下:
3.5 全局过滤器(GlobalFilter)
3.5.1 什么是全局过滤器,为什么需要全局过滤器
1)全局过滤器能够处理一切进入网关的请求和微服务相应,与GatewayFilter的作用是一致的。
2)与GatewayFilter的区别:GatewayFilter是通过配置文件实现的,处理逻辑固定;GlobalFilter的逻辑需要自己写代码实现,更加灵活!
3.5.2. 全局过滤器的实现方式
1)实现GlobalFilter接口:
全局过滤器 GlobalFilterpublic interface GlobalFilter { /** *处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理** @param exchange 请求上下文,里面可以获取Request、Response等信息* @param chain 用来把请求委托给下一个过滤器 * @return {@code Mono} 返回标示当前过滤器业务结束*/ Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);}
2)添加@Order注解或者实现Ordered接口:为了给过滤器进行优先级排序
3)编写处理逻辑
4)添加注解@Component,注入bean中,方便使用
3.5.3. 全局过滤器的实现案例
- 问题说明:定义全局过滤器,拦截并判断用户身份
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
参数中是否有authorization,
authorization参数值是否为admin
- 参数中是否有authorization,
- authorization参数值是否为admin
- 如果同时满足则放行,否则拦截
- 逻辑实现
五步走:
(1)获取请求参数
(2)获取authorization参数
(3)校验
(4)放行
(5)禁止访问/结果处理
3.5 过滤器的执行顺序
三种过滤器:当前路由过滤器,DefaultFilter过滤器,GlobalFilter
- 首先根据指定的order值进行比较:order值越小,优先级越高,执行顺序越靠前。
1)GlobalFilter通过实现Odered接口,或者添加@Order注解指定order值,有我们自己指定
2)路由过滤器和defaultfilter过滤器的order的值由Spring指定,默认是按照声明顺序从1开始递增
3)在order值相同时,会按照:defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行
3.6 限流过滤器
- 作用:限流是保护服务器,避免因为过多的请求而导致服务器过载或者宕机
- 限流算法:计算机算法,漏桶算法,令牌桶算法。
3.7 小总结
网关其实并不需要改变其他服务中的代码,只是一个额外的功能,单独在网关服务中,其实现的原理有:
1)首先生成一个网关服务,添加启动类
2)引入注册发现依赖,引入网关依赖
3)网关的过滤作用在配置文件中声明实现(路由过滤器和defaultfilter,都是申明式的)
4)通过GlobalFilter过滤器实现:通过添加一个类,继承GlobalFilter接口,再书写逻辑,可以更加灵活的操作。
在微服务体系中,配置文件和依赖非常重要
参考文献
1)黑马程序员SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课
图片:
红色字体
用于复制