feign
feign的作用
feign的用法
feign整合ribbon
feign整合hystrix
feign的优化
gateway
gateway的作用
gateway的路由
gateway的过滤器
Feign的简介
SpringCloud提供的声明式的REST客户端,实现远程的服务的调用,只需要编写接口和SpringMVC的注解就能完成调用。
Feign = RestTemplate + Ribbon + Hystrix
Feign的用法
- 引入依赖 openfeign
- 在启动类上加 @EnableFeignClients(“Feign接口所在的包名”)
- 编写Feign接口,在接口上加@FeignClient(“被调用的服务名”)
- 在Feign接口中编写方法(对应提供者的方法),方法可以使用SpringMVC的注解
/**
* 调用商品服务的Rest客户端
*/
@FeignClient("product-service")
public interface ProductFeignClient {
/**
* 调用商品服务的查询方法
*/
@GetMapping("/product/{id}")
ResponseEntity<Product> findProductById(@PathVariable("id")Long id);
}
- 注入接口对象,通过方法实现远程调用
@Autowired
private ProductFeignClient productFeignClient;
@GetMapping("/order/{id}")
public ResponseEntity<Order> findOrderById(@PathVariable("id")Long id){
//模拟订单数据
Order order = new Order(id,99L,null);
//调用商品服务获得商品
ResponseEntity<Product> entity = productFeignClient.findProductById(8L);
order.setProduct(entity.getBody());
return ResponseEntity.ok(order);
}
练习:给商品服务编写增删改查的所有方法,在订单服务中通过Feign分别进行调用,在单元测试中调用
Feign的原理
实现步骤:
- 在启动类上加@EnableFeignClients启动Feign的功能,就会启动对Feign接口的扫描
- 扫描到@FeignClient注解接口,读取接口上的服务名、URL,包装后发给IOC容器
- 由IOC容器通过动态代理机制创建RequestTemplate对象,发送Http请求,交给Http客户端处理
- Http客户端被封装到LoadBalanceClient负载均衡客户端中,交给Ribbon处理
Feign整合Ribbon
Feign默认整合了Ribbon实现负载均衡
全局配置
ribbon.属性 = 值
指定服务配置
服务名称.ribbon.属性 = 值
Ribbon常用配置:
ConnectionTimeout 连接超时
ReadTimeout 读取超时
OkToRetryOnAllOperations 对所有操作启动重试机制 true/false
MaxAutoRetries 最大重试次数
MaxAutoRetriesNextServer 最大重试下个服务器次数
Feign整合Hystrix
Feign默认整合了Hystrix的熔断机制
Feign可以单独定义类,编写降级方法
实现:
1)定义降级处理类,继承对应的FeignClient接口
2)实现接口中的方法,所有方法均为回退方法
3)在FeignClient注解中配置降级方法处理类
fallback = GoodsServiceFallback.class
4)启动Feign的Hystrix特性
feign.hystrix.enabled=true
/**
* goods-service的调用的降级处理类
*/
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public ResponseEntity<Goods> getGoodsById(Long id) {
return ResponseEntity.ok(new Goods(-1L,"降级数据",0.0));
}
...
}
@FeignClient(value = "goods-service",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {...}
Feign的优化配置
Feign的优化配置
1. 优化连接池
Feign是基于HTTP协议,HTTP协议基于TCP协议,TCP具有三次握手四次挥手机制,频繁的创建连接比较消耗系统的资源和时间,降低系统的吞吐量。
使用连接池可以减少网络连接的创建,提高连接的使用效率,提高系统吞吐量。
Feign默认使用JDK自带的HttpURLConnection,没有连接池。可以使用HttpClient或OKHTTP
使用步骤:
1)导入httpclient、feign-httpclient依赖
2)feign.httpclient.enable = true
2. 请求压缩优化
Feign可以对网络数据进行GZIP压缩,减少网络流量,提高速度
启动压缩:
#启动请求压缩
feign.compression.request.enabled=true
#启动响应压缩
feign.compression.response.enabled=true
#设置请求压缩的多媒体类型
feign.compression.request.mime-types=text/html,application/xml,application/json
#设置请求压缩的下限 (默认2048)
feign.compression.request.min-request-size=1024
3. 使用日志对连接过程进行监控
1)开启debug日志
logging.level.包名.FeignClient接口名 = DEBUG
2)定义配置类,配置日志
/** Feign日志配置 */
@Configuration
public class FeignLoggerConfig {
/** 返回日志类型,NONE没有日志,BASIC基本信息(请求方法,URL,响应代码等),HEADERS(头部信息),FULL(基本+头部)*/
@Bean
public Logger.Level level(){
return Logger.Level.BASIC;
}
}
4. 超时优化
Ribbon是具有重试机制的,就是连接失败后进行重连,问题是:Hystrix的超时时间默认是小于Ribbon的超时,Hystrix会提前熔断,Ribbon无法进行重试
Hystrix的超时要大于Ribbon的超时
# hystrix的超时
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
# ribbton的超时
ribbon.ConnectionTimeout=1000
ribbon.ReadTimeout=3000
Gateway的简介
Gateway是SpringCloud中的API网关,提供鉴权和路由的功能
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ycZSkm0I-1654905284481)(feign&gateway.assets/image-20211215152351396.png)]](https://img-blog.csdnimg.cn/c49d544552314ad5852573e32a30108e.png)
Gateway的工作机制
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7bh8tJDW-1654905284482)(feign&gateway.assets/image-20211215152426903.png)]](https://img-blog.csdnimg.cn/4445de24a4e44c80bd4b33949c76a968.png)
- 客户端发送请求给Gateway网关,网关将请求发送给处理器映射(HandlerMapping)
- 网关通过路由的匹配,将请求发送给Web处理器处理,请求就需要经过一系列过滤器
- 过滤器分为“pre"前置和”post"后置两种,前置过滤器实现鉴权作用,后置过滤实现性能统计或日志收集
- 通过过滤器就到达需要的服务
Gateway的路由
GateWay路由规则
时间点后匹配
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
时间点前匹配
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
时间区间匹配
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
指定Cookie正则匹配指定值
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
指定Header正则匹配指定值
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
请求Host匹配指定值
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
请求Method匹配指定请求方式
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
请求路径正则匹配
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
请求包含某参数
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
请求包含某参数并且参数值匹配正则表达式
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
远程地址匹配
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
使用注册中心时,uri以 lb: //开头(lb代表从注册中心获取服务),后面是需要转发到的服务名称
使用方法:
1)创建网关项目, 引入eureka-client和gateway依赖
2)编写配置
server:
port: 9999
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: goods-service-route
uri: lb://goods-service
predicates:
- Path=/goods/**
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/order/**,/orders/**
eureka:
client:
register-with-eureka: true
fetch-registry: true
serviceUrl:
defaultZone: http://localhost:8888/eureka
Gateway的过滤器
从过滤器生命周期(影响时机点)的角度来说,主要有两个pre和post:
| 生命周期时机点 | 作用 |
|---|---|
| pre | 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 |
| post | 这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。 |
从过滤器类型的角度,Spring Cloud GateWay的过滤器分为GateWayFilter和GlobalFilter两种
| 过滤器类型 | 影响范围 |
|---|---|
| GateWayFilter | 应用到单个路由上 |
| GlobalFilter | 应用到所有的路由上 |
/**
* 自定义全局过滤器,用于用户权限验证
*/
@Slf4j
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {
//过滤请求和响应
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获得请求和响应
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获得请求参数 如果有token=123456 就表示登录
String token = request.getQueryParams().getFirst("token");
log.info("url==>"+request.getURI());
log.info("token==>"+token);
if(!"123456".equals(token)){
//如果没有参数token=123456,拒绝访问
response.setStatusCode(HttpStatus.UNAUTHORIZED);
String msg = "Request Denied!!";
DataBuffer wrap = response.bufferFactory().wrap(msg.getBytes());
return response.writeWith(Mono.just(wrap));
}
//如果有就放行
return chain.filter(exchange);
}
//返回过滤器顺序,越小越靠前
@Override
public int getOrder() {
return 0;
}
}
作业
使用Vue展示订单数据(包含商品)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ucdh3YgD-1654905284483)(feign&gateway.assets/image-20211215164851927.png)]](https://img-blog.csdnimg.cn/927cd0852328465ea98fbe540b071b6e.png)
[