zoukankan      html  css  js  c++  java
  • Spring Cloud Alibaba学习笔记(4)

    什么是Feign

    Feign是一个声明式Web Service客户端。
    使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。
    Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

    Feign的组成

    接口 作用 默认值
    Feign.Builder Feign的入口 Feign.Builder
    Client Feign底层用什么去请求 和Ribbon配合时:LoadBalancerFeignClient(代理模式,可以为Feign引入连接池) 不和Ribbon配合时:Fgien.Client.Default(URLConnection,没有连接池,没有资源管理,性能较差)
    Contract 契约,注解支持 SpringMVCContract
    Encoder 解码器,用于将独享转换成HTTP请求消息体 SpringEncoder
    Decoder 编码器,将相应消息体转成对象 ResponseEntityDecoder
    Logger 日志管理器 Slf4jLogger
    RequestInterceptor 用于为每个请求添加通用逻辑

    整合Feign

    在pom.xml文件中添加依赖

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

    在启动类上添加@EnableFeignClients注解

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    import tk.mybatis.spring.annotation.MapperScan;
    
    // 扫猫Mybatis哪些包里面的接口
    @MapperScan("com.example")
    @SpringBootApplication
    @EnableFeignClients
    public class Study01Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Study01Application.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    
    }
    

    使用Feign实现远程http调用

    创建feignClient包,用来存放Feign接口,因为我整合过程中调用的是comment接口,所以创建CommentFeignClient接口类。
    添加注解@FeignClient,表明这个接口是一个FeignClient,指定name,name是要请求的微服务的名称。
    这时,就可以在接口中添加方法了,方法注解参照spring mvc的注解,代码如下:

    @FeignClient(name = "study02")
    public interface CommentFeignClient {
        @GetMapping("/find")
        DemoComment find();
    }
    

    在前文中,微服务A如果要调用微服务B的请求,参考代码如下:

    private final DiscoveryClient discoveryClient;
    private final RestTemplate restTemplate;
    
    public DemoComment findById() {
        // 获取请求示例
        List<ServiceInstance> instances = discoveryClient.getInstances("study02");
        List<String> collect = instances.stream()
                .map(instance -> instance.getUri().toString() + "/find")
                .collect(Collectors.toList());
        // 随机算法
        int i = ThreadLocalRandom.current().nextInt(collect.size());
        String targetURL =  collect.get(i);
        DemoComment forObject = restTemplate.getForObject("http://study02/find", DemoComment.class, 1);
        return forObject;
    }
    

    其中, DemoComment forObject = restTemplate.getForObject("http://study02/find", DemoComment.class, 1);是具体的请求代码,我们借用RestTemplate接口实现了服务间的请求调用。
    那么,利用Feign又如何做到呢?

    • 首先,我们将restTemplate注入更换为刚刚添加的CommentFeignClient注入
    • 然后直接使用commentFeignClient.***()调用请求就可以了。

    代码如下:

    private final DiscoveryClient discoveryClient;
    private final CommentFeignClient commentFeignClient;
    
    public DemoComment findById() {
        DemoComment forObject = commentFeignClient.find();
        return forObject;
    }
    

    Feign的配置

    和Ribbon一样,Feign也支持两种配置方式:java代码方式及配置属性模式

    Feign支持的配置项

    代码支持的配置项

    配置项 作用
    Logger.Level 指定日志级别
    Retryer 指定重试策略
    ErrorDecoder 指定错误解码器
    Request.Options 超时时间
    Collection 拦截器
    SetterFactory 用于设置Hystrix的配置属性,Fgien整合Hystrix才会用

    属性支持的配置项

    feign:
      client:
        config:
          feignName:
            connectTimeout: 5000  # 相当于Request.Optionsn 连接超时时间
            readTimeout: 5000     # 相当于Request.Options 读取超时时间
            loggerLevel: full     # 配置Feign的日志级别,相当于代码配置方式中的Logger
            errorDecoder: com.example.SimpleErrorDecoder  # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
            retryer: com.example.SimpleRetryer  # 配置重试,相当于代码配置方式中的Retryer
            requestInterceptors: # 配置拦截器,相当于代码配置方式中的RequestInterceptor
              - com.example.FooRequestInterceptor
              - com.example.BarRequestInterceptor
            # 是否对404错误解码
            decode404: false
            encode: com.example.SimpleEncoder
            decoder: com.example.SimpleDecoder
            contract: com.example.SimpleContract
    

    下面以feign的日志级别自定义为例展示feign的配置

    细粒度配置

    Java代码

    首先,添加Feign配置类,可以添加在主类下,但是不用添加@Configuration。如果添加了@Configuration而且又放在了主类之下,那么就会所有Feign客户端实例共享,同Ribbon配置类一样父子上下文加载冲突;如果一定添加@Configuration,就放在主类加载之外的包。建议还是不用加@Configuration。

    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    
    public class DemoFeignConfiguration {
        @Bean
        public Logger.Level level() {
            // 让Feign打印所有请求的细节
            return Logger.Level.FULL;
        }
    }
    

    然后,给@FeignClient添加配置类

    @FeignClient(name = "study02", configuration = DemoFeignConfiguration.class)
    public interface CommentFeignClient {
        @GetMapping("/find")
        DemoComment find();
    }
    

    因为示例的是日志级别自定义,而feign的日志级别是建立在feign的接口的日志级别是debug的基础上的,所以需要添加配置属性

    logging:
      level:
        #需要将FeignClient接口全路径写上
        com.example.study01.feignClient.CommentFeignClient: debug
    

    配置属性

    feign:
      client:
        config:
          #想要调用的微服务名称,不是本身
          study02:
            loggerLevel: FULL
    

    全局配置

    Java代码

    在启动类上为@EnableFeignClients注解添加defaultConfiguration配置

    @EnableFeignClients(defaultConfiguration = DemoFeignConfiguration.class)
    

    配置属性

    feign:
      client:
        config:
          #将调用的微服务名称改成default就配置成全局的了
          default:
            loggerLevel: FULL
    

    优先级:细粒度属性配置 > 细粒度代码配置 > 全局属性配置 > 全局代码配置

    打印出来的信息如下:

    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] <--- HTTP/1.1 200 (425ms)
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] content-type: application/json;charset=UTF-8
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] date: Tue, 22 Oct 2019 06:55:41 GMT
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] transfer-encoding: chunked
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] 
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] {"id":1,"typeId":0,"valueId":1152101,"content":"MTE=","addTime":1504933578,"status":0,"userId":15}
    2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] <--- END HTTP (98-byte body)
    2019-10-22 14:55:42.142  INFO 31468 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: study02.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
    

    Feign多参数请求构造

    GET请求

    使用@SpringQueryMap

    @FeignClient(name = "study02")
    public interface CommentFeignClient {
        @GetMapping("/find")
        public DemoComment query(@SpringQueryMap DemoComment comment);
    }
    

    使用 @RequestParam

    @FeignClient(name = "study02")
    public interface CommentFeignClient {
        @RequestMapping(value = "/find",method = RequestMethod.GET)
        public DemoComment query(@RequestParam("id") Long id, @RequestParam("name") String name);
    }
    

    使用Map构建(不推荐)

    @FeignClient(name = "study02")
    public interface CommentFeignClient {
        @RequestMapping(value = "/find",method = RequestMethod.GET)
        public DemoComment query(@RequestParam Map<String,Object> map);
    }
    

    POST请求

    服务提供者方法

     @PostMapping("/save")
        public DemoComment save(@RequestBody DemoComment comment){
            return null;
        }
    

    服务调用者

    @FeignClient(name = "study02")
    public interface CommentFeignClient {
        @RequestMapping(value = "/save",method = RequestMethod.POST)
        public DemoComment query(@RequestBody DemoComment comment);
    }
    

    Feign性能优化

    配置连接池

    apache httpClient

    添加依赖

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

    添加配置

    feign:
      httpclient:
        # 让feign使用apache httpclient作请求
        enabled: true
        # feign的最大连接数
        max-connections: 200
        # feign单个路径的最大连接数
        max-connections-per-route: 50
    

    okHttp

    加依赖

    <dependency>
        <groupId>io.github.openfeign</groupId>
         <artifactId>feign-okhttp</artifactId>
        <version>1.10<version>
    </dependency>
    

    添加配置

     httpclient:
        # feign 最大连接数
        max-connections: 200
        # feign 单个路径请求的最大连接数
        max-connections-per-route: 50
      okhttp:
        enabled: true
    

    合理使用Feign日志

    生产环境使用 Logger.Level.BASIC

  • 相关阅读:
    Socket开发框架之消息的回调处理
    Socket开发框架之数据加密及完整性检查
    Socket开发框架之数据传输协议
    Socket开发框架之框架设计及分析
    C#进行Visio二次开发之文件导出及另存Web页面
    Winform混合式开发框架的特点总结
    代码生成工具Database2Sharp中增加视图的代码生成以及主从表界面生成功能
    基于Metronic的Bootstrap开发框架经验总结(9)--实现Web页面内容的打印预览和保存操作
    基于C#的MongoDB数据库开发应用(4)--Redis的安装及使用
    基于C#的MongoDB数据库开发应用(3)--MongoDB数据库的C#开发之异步接口
  • 原文地址:https://www.cnblogs.com/fx-blog/p/11714109.html
Copyright © 2011-2022 走看看