title: OpenFeign实现远程调用
tag: 笔记 微服务组件
OpenFeign实现远程调用
在之前,我们一个服务调用注册中心其它服务的接口时需要我们编写大量的逻辑来完成远程调用,比如使用RestTemplate
实现的远程调用:
- 注入
RestTemplate
- 通过服务发现
discoveryClient
拿到其它微服务的地址 - 拼接地址,发起http请求
- 封装返回值
这样每一次远程调用都会在代码中留下大量的远程调用逻辑,让开发人员难以专注于业务功能。因此我们应该寻找一个能够将远程调用代码进行封装的组件,简化我们的代码。
而OpenFeign
就是目前流行微服务组件。
OpenFeign快速入门
我们还是以之前实现的购物车和商品服务作为例子,优化之前由RestTemplate
完成的远程调用,这样更能感受到OpenFeign的简洁。
引入依赖
在购物车微服务的pom文件中引入OpenFeign
的依赖和loadBalancer
依赖:
<!--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>
loadBalancer
:在对微服务的调用中需要用到负载均衡,这个依赖内置了负载均衡的各自策略。
在启动类启用OpenFeign
在Cart微服务的启动类上加入注解@EnableFeignClients
来支持OpenFeign组件。
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
@EnableFeignClients
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
编写OpenFeign客户端
@FeignClient("item-service")
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
-
可以看到这里的接口编写与SpringMVC的Controller接口的编写非常相似,降低了我们的学习成本。
-
@FeignClient("item-service")
注解指定了提供服务的微服务 -
ItemClient
仅仅只是一个接口,我们很容易想到SpringCloud是通过接口生成动态代理对象并注册到IOC容器中,这样我们就可以通过注入使用ItemClient
使用FeignClient
编写了OpenFeign
客户端之后就可以在代码中调用ItemClient
编写的接口:
List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
在使用了OpenFeign
现在我们只需要这样一行代码就可以完成远程调用。
使用连接池
Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:
- HttpURLConnection:默认实现,不支持连接池
- Apache HttpClient :支持连接池
- OKHttp:支持连接池
因此我们通常会使用带有连接池的客户端来代替默认的HttpURLConnection。比如,我们使用OK Http.
引入依赖
在cart-service
的pom.xml
中引入依赖:
<!--OK http 的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
开启连接池
在cart-service
的application.yml
配置文件中开启Feign的连接池功能:
feign:
okhttp:
enabled: true # 开启OKHttp功能
重启服务,连接池就生效了。
优化OpenFeign使用
我们这样在一个微服务内编写了一个FeignClient
,如果其它微服务也需要调用这个微服务的接口我们又需要再编写一个FeignClient
。这样就出现了重复代码,我们消除重复代码的一般可以通过抽取到一个公共模块来实现。我们可以在一个API模块里面编写微服务需要的远程调用接口。
抽取Feign客户端
我们首先新建一个模块,并导入依赖:
<!--open feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- load balancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
之后将之前实现的ItemClient复制到api模块下:
指定FeignClient扫描包
现在我们就可以让微服务项目依赖于api模块来实现远程调用了,但现在由于微服务模块不能扫描到FeignClient
所以SpringBoot无法对FeignClient
实现自动装配,因此我们需要指定FeignClient
扫描路径(与Mybatis
的Mapper
扫描路径相似):
我们在Cart-Service的启动类上添加注解:
@EnableFeignClients(basePackages = "com.duan.api.client")
其中basePackages
属性就是指定包扫描路径,我们同样可以使用basePackageClasses
属性来直接指定FeignClient
:
@EnableFeignClients(basePackageClasses = ItemClient.class)
现在Springboot
启动时就会自动扫描包下或者指定接口并为这个FeignClient
创建代理对象加入到IOC容器中,我们就可以通过注入使用
eClasses属性来直接指定
FeignClient`:
@EnableFeignClients(basePackageClasses = ItemClient.class)
现在Springboot
启动时就会自动扫描包下或者指定接口并为这个FeignClient
创建代理对象加入到IOC容器中,我们就可以通过注入使用
FeignClient
了。