SpringCloud系列之-深入理解Feign

Feign介绍

       Feign是一个声明式的web service客户端,它使得编写web service客户端更为容易。创建接口,为接口添加注解,即可使用Feign。Feign可以使用Feign注解或者JAX-RS注解,还支持热插拔的编码器和解码器。Spring Cloud为Feign添加了Spring MVC的注解支持,并整合了Ribbon和Eureka来为使用Feign时提供负载均衡。核心就是通过一系列的封装和处理(动态代理:将这些本地Proxy代理实例,注入到Spring IOC容器中。当远程接口的方法被调用,由Proxy代理实例去完成真正的远程访问,并且返回结果),将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVABEAN,返回给调用者。核心流程图如下:

Feign工作原理

  • SpringBoot启动类添加@EnableFeignClients注解,Spring容器会扫描标记了@FeignClient注解的接口,并生成此接口的代理对象去执行处理调用;
  • @FeignClient(value = "XC_SERVICE_MANAGE_CMS")即指定了cms的服务名称,Feign会从注册中心获取cms服务列表,并通过负载均衡算法进行服务调用;
  • 在接口方法中如果拼接有参数,FeignClient的方法中需要使用注解@PathVariable("XXX") 或 @RequestParam("XXX"),指定调用的url,Feign将根据url进行远程调用;

Feign核心组件及特性

feign核心组件:

(1)Client.Default类:默认的feign.Client 客户端实现类,内部使用HttpURLConnnection 完成URL请求处理。虽然在JKD1.8中HttpURLConnnection 的底层使用了非常简单的HTTP连接池技术,但是,其HTTP连接的复用能力,实际是还是非常弱的,所以接口的性能当然也很低;
(2)ApacheHttpClient 类:内部使用 Apache httpclient 开源组件完成URL请求处理的feign.Client 客户端实现类。

  • 从开发角度而言,Apache HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅使客户端发送Http请求变得容易,而且也方便开发人员测试接口。既提高了开发的效率,也方便提高代码的健壮性;
  • 从性能的角度而言,Apache HttpClient带有连接池的功能,具备优秀的HTTP连接的复用能力。关于带有连接池Apache HttpClient的性能提升倍数;
  • ApacheHttpClient 类处于 feign-httpclient 的专门jar包中,如果使用,还需要通过Maven依赖或者其他的方式,倒入配套版本的专门jar包;

(3)OkHttpClient类:内部使用 OkHttp3 开源组件完成URL请求处理的feign.Client 客户端实现类。OkHttp3 开源组件由Square公司开发,用于替代HttpUrlConnection和Apache HttpClient。由于OkHttp3较好的支持 SPDY协议(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验),从Android4.4开始,google已经开始将Android源码中的 HttpURLConnection 请求类使用OkHttp进行了替换。也就是说,对于Android 移动端APP开发来说,OkHttp3 组件,是基础的开发组件之一。
(4)LoadBalancerFeignClient 类:内部使用 Ribben 负载均衡技术完成URL请求处理的feign.Client 客户端实现类。LoadBalancerFeignClient 在原理上,简单的使用了delegate包装代理模式,Ribben负载均衡组件计算出合适的服务端server之后,由内部包装 delegate 代理客户端完成到服务端server的HTTP请求,所封装的 delegate 客户端代理实例的类型,可以是 Client.Default 默认客户端,也可以是 ApacheHttpClient 客户端类或OkHttpClient 高性能客户端类,还可以其他的定制的feign.Client 客户端实现类型。

feign特性:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP编码器和解码器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的负载均衡;
  • 支持HTTP请求和响应的压缩;

Feign使用

1. pom引入启动类添加注解@EnableFeignClients

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>9.5.1</version>
        </dependency>

2. client详情

// client实体
@FeignClient(
        name = "TestClient",
        url = "http://localhost:8080",
        fallbackFactory = TestApiFailBack.class,
        configuration = TestApiClientConfiguration.class,
        decode404 = true
)
@RequestMapping("/test")
public interface HiqApiClient {

    /**
     * 查询用户信息
     *
     * @param dto userID
     * @return 用户信息
     */
    @PostMapping("/user/info/get")
    Result<UserVO> getUserInfo(@RequestBody UserDTO dto);
}


// 配置类
@Slf4j
public class TestApiClientConfiguration implements RequestInterceptor {

    @Value("${tokenKey}")
    private String apiKey;

    @Override
    public void apply(RequestTemplate template) {
        String param = template.toString();
        log.info("调用Test " + template.url() + " 入参:{}", param.replace(param.split("\\{")[0], ""));
        template.header("Content-Type", "application/json;charset=utf-8");
        template.header("X-Gaia-Api-Key", apiKey);
    }
}


// 回调
@Slf4j
@Component
public class TestApiFailBackimplements FallbackFactory<TestClient> {

    @Override
    public TestClient create(Throwable throwable) {
        return new TestClient() {
            @Override
            public Result<UserVO> getStudentStatus(UserDTO dto) {
                return fail(dto, throwable);
            }

        };
    }

    public <T> Result<T> fail(Object param, Throwable throwable) {
        String methodPath = ClassUtil.getMethodPath(TestClient.class);
        log.error("调用TEST {} 错误:{} param:{}", methodPath, throwable.getMessage(), JSON.toJSONString(param));
        return HIqResult.error("请联...");
    }
}

3. 服务调用

@Slf4j
@Service
public class RpcService {

    @Autowired
    TestClient testClient;

    /**
     * 获取客户信息
     */
    public List<UserInfoResult > getUserInfo(String userId, String userName) {
        UserDTO param = new UserDTO ()
                .setId(userId)
                .setName(userName);
        Result<List<UserVO>> hIqResult = testClient.getUserInfo(param);
        if (hIqResult.success()) {
            return hIqResult.getData().stream().map(RpcService ::build).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    static UserInfoResult build(UserVO info) {
        return new UserInfoResult ()
                .setUserId(info.getId())
                .setUserMobile(info.getMobilephone())
                .setUserName(info.getName());
    }

}

Feign源码的github地址:https://github.com/OpenFeign/feign

如有披露或问题欢迎留言或者入群探讨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值