一 feign
集成了ribbon负载均衡功能,集成了hystrix熔断器功能。支持请求压缩
1 使用feign替代resttemplate发送rest请求
1)在consumer中导入依赖openfeign
2)创建feign客户端,面向接口编程,@feignclient注解,属性赋值服务名;方法上写方法请求映射。feign通过动态代理生成实现类
3) 控制层,注入Feign客户端接口,面向接口编程调用方法实现远程调用服务提供者的对应方法
4)启动类使用 `@EnableFeignClients`注解开启feign
接收路径携带参数变量不能省略赋值,@PathVariable路径变量、@RequestParam请求参数
int login(@RequestParam("s") String s); //这里是参数变量用@RequestParam("s")注解,路径变量则用@PathVariable("s")
//可以传递普通参数,不能传递Java对象,Java对象只能转换为json字符串格式
2 负载均衡
用resttemplate还要加上@loadbalanced注解
配置文件
# 修改服务地址轮询策略,默认是轮询,配置之后变随机 # MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到,一起来规律是1=2,2 2=2,4 3=4,4 4=4,6 5=6,6) user-provider: ribbon: #轮询 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule ConnectTimeout: 10000 # 连接超时时间,比如修改服务提供者的ip让你连不上那你消费者肯定连接超时报错 ReadTimeout: 2000 # 数据读取超时时间,这个是连上服务提供者,然后服务器提供者程序执行超过2秒报错 MaxAutoRetries: 1 # 最大重试次数(第一个服务),比如连上了,但读取超时再重去尝试读取1次,控制器被访问↓ MaxAutoRetriesNextServer: 0 # 最大重试下一个服务次数(集群的情况才会用到,一起来规律在上↑) OkToRetryOnAllOperations: false # 无论是请求超时或者socket read timeout等情况都进行重试
3 熔断器
也就是发生故障不走动态代理生成的实现类,走自定义的接口实现类来降级
1)配置文件开启feign熔断器支持
feign: hystrix: enabled: true # 开启Feign的熔断功能
2)熔断降级类
实现接口:自定义方法体。注意实现类需加上@component注解,才能把对象交给spring容器。
也可以采用内部类方式
3)在接口@feignclient注解内给属性fallback赋值来指定降级类
4 feign压缩yml配置
对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
通过配置开启请求与响应的压缩功能compression:
feign: compression: request: enabled: true # 开启请求压缩 response: enabled: true # 开启响应压缩
也可对请求数据类型,及触发压缩上下限进行设置
5 feign日志级别配置类
普通日志等级配置
# com.ywj 包下的日志级别都为Debug
logging:
level:
com.ywj: debug
feign日志等级配置。除了使用配置类,也可以在启动类内通过@bean注入给spring容器管理。
@Configuration//配置类注解! public class FeignConfig { /** * 日志级别 * @return */ @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
二 spring cloud gateway网关
核心:过滤,路由
同样作为一个微服务,需注册到eureka;工程pom文件导入网关依赖及eureka客户端依赖;启动类添加开启发现客户端注解;配置文件,端口,应用名,eureka地址
1 路由配置
静态路由--动态路由
局部过滤器--全局过滤器
spring: cloud: gateway: routes: # id唯一标识,可自定义 - id: gate-service-route #路由服务地址 #静态路由策略 # uri: http://localhost:18081 #动态,lb协议表示从Eureka注册中心获取服务请求地址,应该用服务名集群访问,会使用负载均衡访问对应服务,负载均衡LoaderBalance uri: lb://user-provider #路由拦截地址配置(断言) predicates: - Path=/** #注意首字母P要是大写的,2个* # 配置局部过滤器 filters: # 请求地址添加路径前缀过滤器 #- PrefixPath=/user # 去除路径前缀过滤器 - StripPrefix=1 - My # 配置全局默认过滤器 default-filters: # 往响应过滤器中加入信息 - AddResponseHeader=X-Response-Default-MyName,ywj
注意:断言,过滤器等关键字key首字母大写。- Path=/** #注意首字母P要是大写的,2个*
2 自定义过滤器
1)全局过滤器
package com.zl.filter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component//这个不能少,创建对象才能调用下面的非静态方法↓ public class LoginGlobalFilter implements GlobalFilter, Ordered { /** * 过滤拦截 * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //获取请求参数 //千万不要点错用这个方法String token = request.getQueryParams().get("token").get(0);//NullPointerException,否则出现空指针异常 String token = exchange.getRequest().getQueryParams().getFirst("token"); System.out.println("通过全局过滤器"); //如果token为空,则表示没有登录 if(StringUtils.isEmpty(token)){ //没登录,状态设置413 exchange.getResponse().setStatusCode(HttpStatus.PAYLOAD_TOO_LARGE); //结束请求 return exchange.getResponse().setComplete(); } //放行 return chain.filter(exchange); } /** * 定义过滤器执行顺序 * 返回值越小,越靠前执行,可以理解为默认从小到大执行 * @return */ @Override public int getOrder() { return 0; } }
2)局部过滤器
自定义局部拦截器,要注意自定义类的前缀用在配置文件,后缀必须是指定工厂后缀
package com.zl.filter; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> { public MyGatewayFilterFactory() { super(MyGatewayFilterFactory.Config.class); } @Override public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("通过局部过滤器"); MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams(); String token = queryParams.getFirst("token"); ServerHttpResponse response = exchange.getResponse(); if (token == null) { return response.setComplete(); } return chain.filter(exchange); } }; } public static class Config { } }