本文介绍了一些关于SpringCloud Feign的基本概念与应用。

RestTemplate

由于微服务架构,无法直接请求其他服务的service,需要远程调用,因此会用到RestTemplate来做远程调用。同时我们使用Ribbon结合RestTemplate来实现使用服务名称代替ip和端口以及负载均衡。Feign则是一种更加优雅的方式,不会需要像RestTemplate一样出现url

使用方法

首先添加依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

然后主启动类上加上@EnableFeignClients注解,就像@EnableEurekaServer注解一样

在Service接口上添加@FeignClient注解,并且指定服务的名称(注册到服务注册中心的名称),因此这里就可以实现跨服务调用,只需要实现注册其他服务的名称的接口。使用起来的整体感觉像controller

@FeignClient(value = "userservice")
public interface UserClient {

@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}

Feign配置

方式一:通过修改yml文件对feign进行配置

#  OrderService
feign:
client:
config:
default:
loggerLevel: FULL

方式二:通过配置类和注解

创建一个configuration类,配置Logger.Level这个Bean,加在指定服务的@FeignClient(value = “userservice”)注解中,或者加在启动类的@EnableFeignClients( defaultConfiguration = xxxconfiguration.class )注解中。

Feign性能优化

Feign底层默认使用的URLConnection,不支持连接池,可以通过使用Apache HttpClient来支持连接池(减少连接的创建与释放)

使用方法

添加HttpClient依赖

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池

feign:
httpclient:
enabled: true # 支持HttpClient的开关
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 单个路径的最大连接数

Feign-Api

controller和FeignClient的重合度较高,可以通过采用定义接口,让二者都去继承这个接口,利用这种方式提供便捷。

存在的问题:紧耦合

我更偏向的方法是将FeignClient、POJO、Feign的默认配置封装到一个模块中,通过引入模块来供其他消费者使用。这样做也可以避免每个服务都要去实现一样的FeignClient,创建实体类等。

存在的问题:有的服务可能仅仅需要部分实体类和功能,有所冗余

使用方法

在其他服务的pom文件中引入该feign-api的依赖,这样就可以引入本模块中未创建的实体类,实现复用

在使用过程中会出现一个问题:对FeignClient的自动装配,@Autowired只能装配项目所在包目录下的Bean,因此需要在@EnableFeignClients注解上添加clients参数。

@EnableFeignClients( clients = {UserClient.class, OrderClent.class}, defaultConfiguration = xxxconfiguration.class ) clients参数可以是数组

总结

流程梳理:

  1. 服务模块不需要实现FeignClient来实现跨服务,不需要创建其他的实体
  2. 通过创建feign-api来对服务进行封装,为其他服务的跨服务调用提供接口,同时减少了实体类重复写的情况

开发流程:

provider的服务相关内容按照springboot一样照常写,然后在provider-api中提供对服务controller的访问,其他服务需要跨服务调用时通过provider-api来从其它服务的controller中获取

题外话

昨晚一直在思考前端到底是如何调用有多个实例的后端服务,为此去了解了一下nginx的负载均衡和反向代理。

我的纠结点在于,我目前学到的springcloud内部的负载均衡都是服务之间的调用,可以通过其他服务的名称向注册中心进行请求,然后再根据返回的服务实例列表负载均衡。那如果这个服务本身我从前端向他发起请求,又应该怎么做才能不访问固定的端口号呢?

最初想到的方法是将对这台主机的http请求,全部向nacos寻找服务名称的这种方式,当然只是我的猜想。今天查资料,貌似是通过向网关发出请求,再由网关进行路由到具体服务。就我个人而言,从设计的角度感觉非常合理,前端的请求可以通过nginx的负载均衡向不同网关实例发送,网关又可以根据url的路径向具体的服务请求,服务则又被注册到了nacos,若存在多个实例也会在openfeign中实现负载均衡。

莫名其妙就串联起来了,学完网关再看看