快速上手
1、引入依赖
在调用方
的项目工程 pom.xml 添加依赖
<!--openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--负载均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
父依赖版本管理
<dependencyManagement>
<dependencies>
<!--spring cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
2、启动OpenFeign
在调用方
的启动类上添加 @EnableFeignClients 注解,启动 OpenFeign 功能
@EnableFeignClients注解参数:
-
basePackages
:需要被调用的API的存放位置(当API位置在默认的扫包范围外时需要配置) -
defaultConfiguration
:需要全局启用的配置(如:日志记录、请求拦截、失败回调…)
@EnableFeignClients(basePackages = "com.hmall.api.client",defaultConfiguration = DefaultFeignConfig.class)
@SpringBootApplication
@MapperScan("com.hmall.cart.mapper")
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
}
3、编写OpenFeign客户端
这里只需要声明接口(被调用方
的方法),无需实现方法。接口中的几个关键信息:
- @FeignClient(“item-service”) :声明服务名称(
被调用方
) - @GetMapping :声明请求方式
- @GetMapping(“/items”) :声明请求路径
- @RequestParam(“ids”) Collection ids :声明请求参数
- List :返回值类型
package com.hmall.cart.client;
import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient("item-service")
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items
发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List。
我们只需要直接调用这个方法,即可实现远程调用了。
4、使用FeignClient
在调用方
注入写好的 OpenFeign 客户端,调用客户端内方法即可!
如:我们在 cart-service 的 com.hmall.cart.service.impl.CartServiceImpl 中改造代码,直接调用 ItemClient 的方法:
feign替我们完成了服务拉取、负载均衡、发送http请求的所有工作。
而且,这里我们不再需要RestTemplate了,还省去了RestTemplate的注册。
5、使用连接池
Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:
- HttpURLConnection:默认实现,不支持连接池
- Apache HttpClient :支持连接池
- OKHttp:支持连接池
在调用方
的 pom.xml 中引入依赖
<!--OK http 的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
在调用方
的 application.yml 配置文件中开启 Feign 的连接池功能
feign:
okhttp:
enabled: true # 开启OKHttp功能
debug在org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient中的execute方法中打断点,即可验证连接池是否生效。
6、日志配置
要让日志级别生效,还需要配置这个类。有两种方式:
- 局部生效:在某个
FeignClient
中配置,只对当前FeignClient
生效
@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
- 全局生效:在
@EnableFeignClients
中配置,针对所有FeignClient
生效。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)
7、Feign拦截器
目的:实现微服务之间传递数据,如用户信息
应用场景:下单的过程中,需要调用商品服务扣减库存,调用购物车服务清理用户购物车。而清理购物车时必须知道当前登录的用户身份。但是,订单服务调用购物车时并没有传递用户信息,购物车服务无法知道当前用户是谁!
这是,Feign 中的拦截器接口:feign.RequestInterceptor
就发挥作用了
public interface RequestInterceptor {
/**
* Called for every request.
* Add data using methods on the supplied {@link RequestTemplate}.
*/
void apply(RequestTemplate template);
}
我们只需要实现这个接口,然后实现 apply 方法,利用 RequestTemplate
类来添加请求头,将用户信息保存到请求头中。这样以来,每次 OpenFeign 发起请求的时候都会调用该方法,传递用户信息。
(由于 FeignClient 全部都是在 hm-api 模块,因此在 hm-api 模块的com.hmall.api.config.DefaultFeignConfig 中编写这个拦截器)
@Bean
public RequestInterceptor userInfoRequestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
// 获取登录用户
Long userId = UserContext.getUser();
if(userId == null) {
// 如果为空则直接跳过
return;
}
// 如果不为空则放入请求头中,传递给下游微服务
template.header("user-info", userId.toString());
}
};
}