文章目录
- Http声明式客户端Feign
- Feign介绍与使用
- Feign自定义配置
- Feign性能优化
- Feign最佳实践方案
- 网关Gateway
- 网关Gateway的作用与搭建
- 路由断言工厂Route Predicate Factory
- 路由过滤器GatewayFilter
- 全局过滤器
- 过滤器执行顺序
- 网关的跨域处理
Http声明式客户端Feign
Feign介绍与使用
RestTemplate方式进行远程调用存在的问题
- 可读性差
- 对复杂url不方便操作
Feign是一个声明式的Http客户端
- 它把远程调用的方式与Spring MVC的Controller相似化了
- 它接入了Ribbon自动实现负载均衡
使用步骤:
- 引入依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在启动类添加@EnableFeignClients开启Feign的自动装配功能,@Enable开头的注解什么意思
- 编写Feign客户端,创建一个接口加上@FeignClient,其利用了SpringMVC的映射注解声明远程调用的信息。
@GetMapping注解在Spring MVC中和Feign中都可以使用,用于定义Restful的接口,但它们的用途不同。在Spring MVC中,它用于将HTTP GET请求映射到指定的处理方法上;而在Feign中,它用于定义Feign客户端接口中的方法,用于向远程服务发送HTTP GET请求。
@FeignClient("userservice") // 指定要请求的服务名称
public interface UserClient {@GetMapping("/user/{id}") // GetMapping是标明请求方式,不仅仅是Controller中的监听Get请求,这里是发送请求的方式User findById(@PathVariable Long id);
}
- 使用客户端进行远程调用
@Resource
private UserClient userClient;User user = userClient.findById(order.getUserId());
Feign自定义配置
方式一:改配置文件
# Feign日志级别
feign:client:config:default:loggerLevel: HEADERS
方式二:在Configuration类中声明一个对应类型的Bean
Feign性能优化
Feign的底层客户端实现有三种:
- URLConnection: 默认实现,不支持连接池
- Apache HttpClient: 支持连接池(这里是Http连接的连接池,与Druid数据库连接池不同)
- OKHttp: 支持连接池
这样我们就可以切换客户端并配置连接池来改善性能
Feign的性能优化可以从下面2个方面入手:
- 使用连接池
- 日志级别设为basic或者none
替换客户端实现为HttpClient:
- 引入HttpClient依赖
<!-- feign的httpclient--><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency>
- 在配置文件中新增连接池配置
feign:client:config:default:loggerLevel: BASIChttpclient:enabled: falsemax-connections: 200max-connections-per-route: 50 # 每个路径的最大连接
Feign最佳实践方案
缺点是会造成紧耦合,并且还需要在实现类中重新写一遍@PathVariable这种注解
缺点是会引入大量的方法,但是并不是都能用得上
抽取Feign为单独模块时,要注意到其他微服务的@ComponentScan是只能扫描到同级别及以下的类,为了让其他微服务扫描到Feign模块中的FeignClient,需要在@EnableFeignClients注解上增加参数(推荐第二种)
网关Gateway
网关Gateway的作用与搭建
- 身份认证,权限校验
- 服务路由,负载均衡
- 请求限流
SpringCloudGateway是响应式编程的网关实现
搭建步骤:
- 新建一个网关的Module,在其中引入依赖
<!-- nacos客户端依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 网关依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
- 编写路由和Nacos地址(application.yml)
server:port: 10010
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848 # nacos服务器地址gateway:routes:- id: user-service # 路由id,自定义,只要唯一即可uri: lb://userservice # 路由的目标地址 lb=LoadBalance负载均衡, 后面跟服务名称,会被nacos注册中心对照为服务地址predicates: # 路由断言,也就是判断哪些请求模式是属于这个路由的- Path=/user/**
- 写好Application启动类
这就搭建完成了,以后请求都发到网关,网关判断后通过注册中心找到对应服务,把请求转过去
路由断言工厂Route Predicate Factory
配置文件中写的断言规则path只是字符串,会被Predicate Factory读取并处理,转变为路由判断条件,之后由对应的断言工厂进行判断,还有其他断言可以使用:
路由过滤器GatewayFilter
网关中的过滤器,可以对进入网关的请求和微服务返回的响应进行处理
过滤器的添加也是在配置文件.yml中,给某服务加过滤器,就修改之前的配置为:
server:port: 10010
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848 gateway:routes:- id: user-service uri: lb://userservice filter:- AddRequestHeader=Greeting, Hello World! # 添加请求头过滤器工厂predicates:- Path=/user/**
如果想给所有的服务都加过滤器,可以用默认过滤器,对所有路由都生效
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848 # nacos服务器地址gateway:routes:......default-filters:- AddRequestHeader=Greeting, Hello world! # 添加请求头
全局过滤器
全局过滤器也是作用于所有请求和微服务响应,与默认过滤器的区别是,它需要自己使用代码实现其逻辑:
- 实现GlobalFilter接口
2. 配置优先级(@Order或者实现Ordered接口)
//@Order(1) 设置过滤器的优先级,越小越高, -1最大,也可以通过实现Ordered接口完成优先级配置
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered{@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){// 1.获取请求参数ServerHttpRequest request = exchange.getRequest();MultiValueMap<String, String> params = request.getQueryParams();// 2.获取参数中的authorization参数String authorization = params.getFirst("authorization");// 3.判断参数值是否等于adminif("admin".equals(authorization)){// 4.相等就放行return chain.filter(exchange);}else{// 5.不等就拦截// 设置状态码exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);// 拦截return exchange.getResponse().setComplete();}}@Overridepublic int getOrder(){ return -1;}
}
过滤器执行顺序
三种过滤器是放在一个集合里排序的,排序规则是:
- 优先级Order的值
- 同优先级按defaultFilter>路由过滤器>GlobalFilter的顺序执行
- GlobalFilter优先级是自己指定的,其他两个是按在配置文件中的书写顺序从1递增的(第一个写的过滤器Order=1,第二个写的Order=2)
为什么三种过滤器可以放在一个集合中排序?
- 路由过滤器和默认过滤器都是GatewayFilter的实现类
- 全局过滤器GlobalFilter会作为参数交给GatewayFilterAdapter的构造函数,而GatewayFilterAdapter是实现了GatewayFilter接口的,相当于把GlobalFilter装饰为了GatewayFilter的实现类
- 所以他们三个能以GatewayFilter实现类的身份加入一个集合
网关的跨域处理
跨域问题:浏览器禁止请求发起者与服务端发生跨域ajax请求,请求被浏览器拦截
浏览器采用同源策略,需要网页和其调用的接口的 协议、域名、端口 都一致,不一致它会觉得有风险。
CORS 是一个 W3C 标准,全称是“跨源资源共享”(Cross-origin resource sharing),或者通俗地
称为“跨域资源共享”。它允许浏览器向跨源的服务器,发出XMLHttpRequest请求,从而克服AJAX
只能同源使用的限制。
网关处理跨域采用的就是CORS,只需要在配置中进行添加:
spring:cloud:gateway:globalcors: # 全局的跨域处理add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题corsConfigurations:'[/**]': # 对所有的请求生效allowedOrigins: # 允许哪些网站的跨域请求- "http://localhost:8090"- "http://www.leyou.com"allowedMethods: # 允许的跨域ajax的请求方式- "GET"- "POST"- "DELETE"- "PUT"- "OPTIONS"allowedHeaders: "*" # 允许在请求中携带的头信息allowCredentials: true # 是否允许携带cookiemaxAge: 360000 # 这次跨域检测的有效期