Feign
RestTemplate调用服务出现的问题
- 掺杂非业务代码
- url难以维护
Feign是一个声明式的http请求客户端,可以帮助我们优雅的实现http请求发送
搭建
- 在服务中添加pom依赖
<!--feign客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 启动类添加注解
@EnableFeignClients
- 添加调用客户端的接口
/**
* 调用userservice客户端的接口
*
* @author Deevan
*/
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
- 在业务中注入
userClient
,并实现远程调用userservice服务
@Autowired
private UserClient userClient;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
//根据id查询订单
Order order = orderService.queryOrderById(orderId);
//利用feign远程调用
User user = userClient.findById(order.getUserId());
//将user加入order并返回
order.setUser(user);
return order;
}
相关配置
优化
使用连接池,减少开销
连接池配置
- 引入依赖
<!--feign连接池HttpClient-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 配置连接池
feign:
client:
config:
default: #defult全局配置
loggerLevel: BASIC #基本的请求和响应
httpclient:
enabled: true #开启Feign对HttpClient的支持
max-connections: 200 #最大连接数
max-connections-per-route: 50 #每个路径的最大连接数
Feign的最佳实现
引入依赖会引入不需要的client接口
项目的启动类只会扫描到自己项目类路径下的类,但是要扫描feign-api下的包。方式一将所有包扫描,方式二指定扫描
@MapperScan("com.xn2001.order.mapper")
@SpringBootApplication
//扫描feign-api中包和开启feign的自动化功能
@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* 将RestTemplate注入spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Gateway
网关
- zuul:基于Servlet,阻塞式编程
- springCloudGateway:基于spring提供的WebFlux,响应式编程,性能好
搭建网关
创建一个module gateway
并加入依赖,创建启动类
<!--Nacos服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--网关gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
编写配置:创建application.yml
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848
gateway:
routes:
- id: user-service #路由标识
uri: lb://userservice #路由的目标地址
predicates: #路由断言:判断请求是否符合规范
- Path=/user/** #判断路径是否以user开头
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
路由断言工厂
使用
网关过滤器
路由过滤器
默认过滤器
全局过滤器
/**
* 登录过滤器
*
* @author Deevan
*/
//过滤器优先级,越小越高
@Order(-1)
@Component
public class LoginFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
//获取参数中author参数
String auth = params.getFirst("author");
if ("admin".equals(auth)) {
//方行
return chain.filter(exchange);
}
//拦截,返回状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
过滤器执行顺序
先看order值,值相等比较过滤器类型
跨域
Feign原理
- 在使用Openfeign时首先会在springboot的启动类上添加
@EnableFeignClients
注解,该注解会导入FeignClientsRegistrar
类,会去扫描所有的带有@FeignClient
- 解析到 @FeignClient 修饰类后,会最终注册一个
FeignClientFacotoryBean
进入 Spring 容器 - Spring 容器在初始化其他用到@FeignClient 接口的类时, 获得的是 FeignClientFacotryBean 产生的一个代理对象 Proxy
- 这个代理对象的调用, 都会被统一转发给 Feign 框架所定义的一个
InvocationHandler
, 由该 Handler 完成后续的 HTTP 转换, 发送, 接收, 翻译HTTP响应的工作