• 关于@FeignClient的属性源码分析


      这段时间一直在用RestTemplate做restful服务的调度,与新同事交流后学到了另外的方式用Feign来调用。以前用dubbo多了,确实对spring-cloud全家桶的认识不足。今天用feign的调用方式将文件服务的相关接口做了改造。但是对@FeignClient注解的相关属性不是很清楚。同时在不指定url的情况下,feign是如何找到服务地址的?带着这两个问题,做了今天的源码解读。接下来做个总结

    一、@FeignClient的各属性解读

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FeignClient {
        /**
         * 说明:
         * 1、value 与 name 互为别名,两者二选一即可
         * 2、当 contextId 没有值的时候,会默认获取(value/name)的值
         * 3、当未指定 url 请求地址的时候,最终会通过 ribbon-loadbalancer工具,从consul注册节点中选取 service-id 等于 value的服务作为请求地址
         * @return
         */
        @AliasFor("name")
        String value() default "";
        /**
         * 说明:
         * 1、serviceId 已经作废,其目的与 value一致。如果设置了 serviceId,则value/name 皆以 serviceId 为准
         */
        /** @deprecated */
        @Deprecated
        String serviceId() default "";
        /**
         * 说明:
         * 1、当 contextId 没有值的时候,会默认获取(value/name)的值
         * 2、当 qualifier 没有值的时候,会将 '${contextId}FeignClient'作为 feign 的bean组件别名
         */
        String contextId() default "";
        /**
         * 说明:同 value, 二选一
         */
        @AliasFor("value")
        String name() default "";
        /**
         * 说明:
         * 1、feign的bean组件别名,拥有最高优先级;
         * 2、当 qualifier 为空时,取 '${contextId}FeignClient' 作为 bean 的名称
         */
        String qualifier() default "";
        /**
         * 说明:
         * 1、设置 url 以后,后续发起http调用时,直接读取该地址作为请求目标;
         * 2、未设置 url 时,借助 ribbon-loadbalancer 组件,根据 (value/name)从consul的服务列表中选中service-id匹配的目标服务;
         */
        String url() default "";
    
        boolean decode404() default false;
    
        Class<?>[] configuration() default {};
    
        Class<?> fallback() default void.class;
    
        Class<?> fallbackFactory() default void.class;
        /**
         * 说明:
         * 目标服务器 对应的资源 uri (FeignClient下所有方法相同的path路径)
         */
        String path() default "";
    
        boolean primary() default true;
    }

    核心源码截图如下

    orgspringframeworkcloudspring-cloud-openfeign-core2.1.5.RELEASEspring-cloud-openfeign-core-2.1.5.RELEASE.jar!orgspringframeworkcloudopenfeignFeignClientsRegistrar.class

      

     二、当FeignClient未设置url时,通过ribbon查找服务的核心方法

    com etflix ibbon ibbon-loadbalancer2.3.0 ibbon-loadbalancer-2.3.0.jar!com etflixclientAbstractLoadBalancerAwareClient.class

     三、使用Feign做restful服务调用的简单示例

    3.1、开启FeignClient的扫描(EnableFeignClients)

    @Configuration
    @EnableFeignClients(basePackages = "com.simm")
    public class FeignConfiguration {
    }

    3.2、设置 RequestInterceptor,统一添加授权的Header

    @Slf4j
    @Component(value = "core_feign_interceptor")
    @AllArgsConstructor
    public class FeignInterceptor implements RequestInterceptor {
        private final ClientTokenTemplate clientTokenTemplate;
    
        /**
         * fengin请求添加header
         * @param requestTemplate
         */
        @Override
        public void apply(RequestTemplate requestTemplate) {
            // 如果token中的类型加入了验证, 则设置rdc token
            Collection<String> authHeaders = requestTemplate.headers().get(TokenConstant.AUTH_TYPE);
            if (CollectionUtils.isNotEmpty(authHeaders) && authHeaders.contains(TokenConstant.CLIENT_AUTH)) {
                requestTemplate.header("Authorization", clientTokenTemplate.getRedisToken().getAccess_token());
            } else {
                AuthInfo authInfo = BizContext.getValue(Constants.BizContextKey.AUTH);
                if(authInfo!=null && !StringUtils.isEmpty(authInfo.getAccess_token())){
                    requestTemplate.header("Authorization", authInfo.getAccess_token());
                }
            }
        }
    }
    View Code

    3.3、文件服务的客户端实现

    /**
     * 文件服务客户端
     *
     * @author simm
     */
    @ConditionalOnProperty(name = {"gateway.host", "gateway.apis.file-service"})
    @FeignClient(value = "rdc-file-service", url = "${gateway.host}/${gateway.apis.file-service}", path = "/api/v2/files")
    public interface RdcFileClient {
        /**
         * 获取文件信息
         *
         * @param fileId 文件ID
         * @return 文件内容
         */
        @GetMapping(value = "/{fileId}", headers = TokenConstant.GATEWAY_AUTH_HEADER)
        PluginFileInfoResponse getFileInfo(@PathVariable String fileId);
    
        /**
         * 上传文件测试
         *
         * @param file 文件
         * @return 文件注册信息
         */
        @PostMapping(value = "/", headers = TokenConstant.GATEWAY_AUTH_HEADER, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        PluginFileInfoResponse uploadFile(MultipartFile file);
    
        /**
         * 获取下载地址
         *
         * @param fileId 文件ID
         * @return
         */
        @GetMapping(value = "/{fileId}/download-url", headers = TokenConstant.GATEWAY_AUTH_HEADER)
        String getDownloadUrl(@PathVariable String fileId);
    
        /**
         * 批量获取文件详情
         *
         * @param object 信息
         * @return
         */
        @PostMapping(value = "/batchInfos", headers = TokenConstant.GATEWAY_AUTH_HEADER,
                produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        List<PluginFileInfoResponse> batchGetFileDetail(JSONObject object);
    
        /**
         * 删除缓存的文件
         *
         * @param fileId 文件ID
         * @return
         */
        @DeleteMapping(value = "/{fileId}", headers = TokenConstant.GATEWAY_AUTH_HEADER)
        Object delFile(@PathVariable String fileId);
    }
    View Code
  • 相关阅读:
    英语语法总结---二、英语中的从句是怎么回事
    【Cocos得知】技术要点通常的积累
    政府采购清单应包括“问题” 积
    Ubuntu通过使用PyCharm 进行调试 Odoo 8.0 可能出现的问题
    Android自己定义组件系列【8】——面膜文字动画
    手机新闻网站,手持移动新闻,手机报client,jQuery Mobile手机新闻网站,手机新闻网站demo,新闻阅读器开发
    OS和android游戏纹理优化和内存优化(cocos2d-x)
    删除重复数据
    MyEclipse2014 设备 checkstyle、PMD、findbugs 最简单的方法 详细说明
    hdu5044 Tree 树链拆分,点细分,刚,非递归版本
  • 原文地址:https://www.cnblogs.com/MrSi/p/14083773.html
Copyright © 2020-2023  润新知