美文网首页
2021-03-06_Feign服务原生调用学习笔记

2021-03-06_Feign服务原生调用学习笔记

作者: kikop | 来源:发表于2021-03-08 07:04 被阅读0次

    Feign服务调用学习笔记

    1概述

    本节简单学习下独立使用Feign的基本用法。Feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Feign底层默认是使用jdk中的HttpURLConnection发送HTTP请求(没有连接池,保持长连接),feign也提供了httpClient、OKhttp来发送请求。

    之所以学习Feign这个功能,主要是考虑:

    1.传统采用httpclient(org.apache.httpcomponents)或者okhttp(io.github.openfeign)这样相对较重的框架,对初学者来说编码量与学习曲线都会是一个挑战。

    2.而使用spring中RestTemplate,又没有配置化的解决方案。

    1.1 Feign底层原理

    feign是一个伪客户端,即它不做任何的请求处理。Feign通过处理注解生成request,从而实现简化HTTP API开发的目的,即开发人员可以使用注解的方式定制request api模板,在发送http request请求之前,feign通过处理注解的方式替换掉request模板中的参数,这种实现方式显得更为直接、可理解。

    2代码实战

    2.1Feign

    2.1.1client

    2.1.1.1maven依赖

    注意点:Feign 10.x 及以上版本是在 Java 8上构建的,应该在 Java 9、10 和 11上工作。对于需要 JDK 6兼容性的用户,请使用 Feign 9.x。

    <!--3.1.feign-core-->
    <!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-core -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-core</artifactId>
        <version>9.6.0</version>
    </dependency>
    
    <!--3.2.feign-jackson-->
    <!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-jackson -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-jackson</artifactId>
        <version>9.6.0</version>
    </dependency>
    

    2.1.1.2远程服务接口

    package com.kikop.mynavivefeign.service.impl;
    
    import com.alibaba.fastjson.JSONObject;
    import feign.Headers;
    import feign.Param;
    import feign.RequestLine;
    
    /**
     * @author kikop
     * @version 1.0
     * @project Name: myspringdemo
     * @file Name: RemoveServiceImpl
     * @desc 远程服务feign包装的接口
     * @date 2021/3/7
     * @time 10:50
     * @by IDE: IntelliJ IDEA
     */
    public interface RemoveServiceImpl {
    
        // 通过@RequestLine指定HTTP协议及URL地址
        @RequestLine("GET /myspringbootdemo/myfeign/say")
        String say();
    
        // 字符串传参示例
        @RequestLine("GET /myspringbootdemo/myfeign/getStrValue?userName={userName}")
        String getStrValue(@Param(value = "userName") String userName);
    
        // JSON对象传参示例
        @Headers({"Content-Type: application/json", "Accept: application/json"})
        @RequestLine("POST /myspringbootdemo/myfeign/getObjectValue")
        JSONObject getObjectValue(JSONObject req);
    
    }
    
    

    2.1.1.3调用测试

    package com.kikop.mynavivefeign.test;
    
    import com.alibaba.fastjson.JSONObject;
    import com.kikop.mynavivefeign.service.impl.RemoveServiceImpl;
    import feign.Feign;
    import feign.Request;
    import feign.Retryer;
    import feign.jackson.JacksonDecoder;
    import feign.jackson.JacksonEncoder;
    
    public class mytest {
    
        public static void main(String[] args) {
            try {
    
                for (int i = 0; i <10 ; i++) {
                    getStrValueTest();
                }
    
            } catch (Throwable ex) {
                System.out.println("----------ex----------");
                ex.printStackTrace();
            }
    
        }
    
        private static void sayTest() {
            RemoveServiceImpl removeService = Feign.builder()
                    // options方法指定连接超时时长及响应超时时长
                    .options(new Request.Options(1000, 3500))
                    // retryer方法指定重试策略:最大3次
                    .retryer(new Retryer.Default(5000, 5000, 3))
                    // target方法绑定接口与服务端地址。返回类型为绑定的接口类型。
                    .target(RemoveServiceImpl.class, "http://127.0.0.1:8085");
            System.out.println(removeService.say());
        }
    
        private static void getStrValueTest() {
            RemoveServiceImpl removeService = Feign.builder()
                    // options方法指定连接超时时长及响应超时时长
                    .options(new Request.Options(1000, 3500))
                    // retryer方法指定重试策略
                    .retryer(new Retryer.Default(5000, 5000, 3))
                    // target方法绑定接口与服务端地址。返回类型为绑定的接口类型。
                    .target(RemoveServiceImpl.class, "http://127.0.0.1:8085");
    
            String kikop = removeService.getStrValue("kikop");
            System.out.println(kikop);
    
        }
    
        private static void getObjectValueTest() {
            RemoveServiceImpl removeService = Feign.builder()
                    // pojo对象编码器 
                    .encoder(new JacksonEncoder())
                    // pojo对象解码器
                    .decoder(new JacksonDecoder())
                    // options方法指定连接超时时长及响应超时时长
                    .options(new Request.Options(1000, 3500))
                    // retryer方法指定重试策略
                    .retryer(new Retryer.Default(5000, 5000, 3))
                    // target方法绑定接口与服务端地址。返回类型为绑定的接口类型。
                    .target(RemoveServiceImpl.class, "http://127.0.0.1:8185");
    
            JSONObject req = new JSONObject();
            req.put("userName", "kikop");
            JSONObject result = removeService.getObjectValue(req);
            System.out.println(result.getString("userName"));
        }
    }
    

    2.1.2server(辅助测试)

    2.1.2.1后台服务接口

    package com.kikop.demo;
    
    import com.alibaba.fastjson.JSONObject;
    import com.kikop.mytech.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    @RequestMapping("/myfeign")
    @RestController
    @SpringBootApplication
    public class DemoApplication {
    
        @Autowired
        private HelloService helloService;
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
    
        }
    
        @RequestMapping("/say")
        public String say() {
            return helloService.say();
        }
    
        // http://localhost:8085/myspringbootdemo/myfeign/getStrValue?userName=kikop
        @RequestMapping(value = "/getStrValue", method = {RequestMethod.GET, RequestMethod.POST})
        @ResponseBody
        public String getStrValue(@RequestParam String userName) {
    
            System.out.println("begin getStrValue...");
            ExecutorService executorService = Executors.newFixedThreadPool(1);
            executorService.execute(new MyTaskHandler());
            System.out.println("end getStrValue!");
            return userName.toUpperCase();
        }
    
        @RequestMapping(value = "/getObjectValue", method = {RequestMethod.GET, RequestMethod.POST})
        @ResponseBody
        public JSONObject getObjectValue(@RequestBody JSONObject user) throws InterruptedException {
            System.out.println("getObjectValue...");
            JSONObject result = new JSONObject();
            result.put("success", true);
            result.put("userName", user.getString("userName").toUpperCase());
    
            System.out.println("getObjectValue!");
            return result;
        }
    
    }
    

    2.1.2.2服务端配置

    server.port=8085
    server.servlet.context-path=/myspringbootdemo
    
    mytech.demo.name=kikop
    mytech.demo.hobby=swim
    

    3总结

    总到来说,Feign的源码实现的过程如下:

    • 首先通过@EnableFeignCleints注解开启FeignCleint
    • 根据Feign的规则实现接口,并加@FeignCleint注解
    • 程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中
    • 当接口的方法被调用,通过jdk的动态代理,来生成具体的RequesTemplate
    • RequesTemplate在生成Request
    • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
    • 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。

    参考

    1.Feign真正正确的使用方法

    https://www.jianshu.com/p/3d597e9d2d67

    2feign更正确的使用方法--结合ribbon

    https://www.jianshu.com/p/37e915bea7c8

    相关文章

      网友评论

          本文标题:2021-03-06_Feign服务原生调用学习笔记

          本文链接:https://www.haomeiwen.com/subject/ukouqltx.html