zoukankan      html  css  js  c++  java
  • Java 开源项目 OpenFeign —— feign 结合 SpringBoot

    1. 前言

    Spring 对 Feign 做了封装,包括常用的 encoder/decoder ,让我们能用 Bean 的形式使用 Feign。我们将沿用之前的代码。

    1.1 Maven 依赖

     1         <dependency>
     2             <groupId>org.springframework.cloud</groupId>
     3             <artifactId>spring-cloud-starter-openfeign</artifactId>
     4         </dependency>
     5         <dependency>
     6             <groupId>org.springframework.cloud</groupId>
     7             <artifactId>spring-cloud-starter</artifactId>
     8         </dependency>
     9 
    10     <dependencyManagement>
    11         <dependencies>
    12             <dependency>
    13                 <groupId>org.springframework.cloud</groupId>
    14                 <artifactId>spring-cloud-dependencies</artifactId>
    15                 <version>Hoxton.SR3</version>
    16                 <type>pom</type>
    17                 <scope>import</scope>
    18             </dependency>
    19         </dependencies>
    20     </dependencyManagement>

    1.2 激活 openfeign

    在 Springboot 启动类加上注解  @EnableFeignClients

    2. SpringMvc 注解

    与原生的 Feign 不同,在 Springboot 中要使用到 SpringMvc 的注解,这存在一些限制(比如动态改变 URL ),需要我们找 workRound 

    2. 编写代码

    由于使用 SpringMVC 风格,编写的代码与 feign 原生的有不少出入,需要仔细对比。

    2.1 改写官方教程

    我们只需要创建与 GitHub 接口相似的代码,与响应的测试代码

    2.1.1 创建 Client

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 @FeignClient(name = "gitHubs", url = " https://api.github.com", qualifier = "gitHubsClient")
     6 public interface GitHubClient {
     7     @GetMapping(value = "/repos/{owner}/{repo}/contributors")
     8     @ResponseBody
     9     List<SimpleGit.Contributor> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo);
    10 
    11     @Data
    12     @JsonIgnoreProperties(ignoreUnknown = true)
    13     class Contributor {
    14         String login;
    15         int contributions;
    16     }
    17 
    18 }

    2.1.2 创建测试代码

     1 @SpringBootTest
     2 class GitHubClientTest {
     3     @Autowired
     4     GitHubClient gitHubClient;
     5 
     6     @Test
     7     void contributors() {
     8         List<SimpleGit.Contributor> contributors = gitHubClient.contributors("OpenFeign", "feign");
     9         Assertions.assertNotNull(contributors);
    10         Assertions.assertNotEquals(0, contributors.size());
    11 
    12     }
    13 }

    2.1.3 动态改变请求 url

    从上边的代码可以看到,我们将 url 写死在了 GitHubClient 中。让我们新增一个方法,增加 URI 类型的参数

    1     @GetMapping(value = "/repos/{owner}/{repo}/contributors")
    2     @ResponseBody
    3     List<SimpleGit.Contributor> contributorsWithURL(URI uri, @PathVariable("owner") String owner, @PathVariable("repo") String repo);

    然后用任意字符串替换 FeignClient#url 并写一个测试:

    1     @Test
    2     void contributorsWithURL() {
    3         List<SimpleGit.Contributor> contributors =    gitHubClient.contributorsWithURL(URI.create("https://api.github.com"), "OpenFeign", "feign");
    4         Assertions.assertNotNull(contributors);
    5         Assertions.assertNotEquals(0, contributors.size());
    6     }

    2.2 改写 DictFeign

    2.2.1 编写 DictClient 接口

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 @FeignClient(
     6         name = "dictClients",
     7         url = "127.0.0.1:8080",
     8         path = "dic",
     9         qualifier = "dictClients"
    10 )
    11 public interface DictClient {
    12     /**
    13      * @see FeignController#details
    14      */
    15     @GetMapping("details")
    16     Dict details();
    17 
    18     /**
    19      * @see FeignController#details
    20      */
    21     @GetMapping("details")
    22     Dict detailsWithURI(URI uri);
    23 
    24 
    25     /**
    26      * @see FeignController#startsWith
    27      */
    28     @GetMapping("startsWith/{query}")
    29     List<String> startsWith(@PathVariable("query") String query);
    30 
    31 
    32     /**
    33      * @see FeignController#updateFirst
    34      */
    35     @PutMapping("updateFirst?target={target}")
    36     List<String> updateFirst(@PathVariable("target") String target);
    37 
    38     /**
    39      * @see FeignController#headers
    40      */
    41     @GetMapping("headers")
    42     Map<String, Object> headers(@RequestHeader Map<String, Object> headers);
    43 
    44     /**
    45      * @see FeignController#startAndEnd
    46      */
    47     @GetMapping("query")
    48     List<String> startAndEnd(@RequestParam Map<String, String> map);
    49 
    50     /**
    51      * @see FeignController#replace
    52      */
    53     @PutMapping(value = "replace", consumes = MediaType.APPLICATION_JSON_VALUE)
    54     List<String> replace(Map<String, String> map);
    55 
    56 
    57     /**
    58      * @see FeignController#add
    59      */
    60     @PostMapping(value = "add", consumes = MediaType.APPLICATION_JSON_VALUE)
    61     List<String> add(Map<String, Object> map);
    62 
    63     /**
    64      * @see FeignController#deleteFirst
    65      */
    66     @DeleteMapping("deleteFirst")
    67     List<String> deleteFirst();
    68 }

    2.2.2 编写对应的测试方法

     1 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
     2 class DictClientTest {
     3     private final Dict dict = Dict.Instance;
     4     @Autowired
     5     private DictClient dictClient;
     6 
     7 
     8     @Test
     9     void details() {
    10         Assertions.assertEquals(dict, dictClient.details());
    11     }
    12 
    13     @Test
    14     void startsWith() {
    15         Assertions.assertEquals(3, dictClient.startsWith("a").size());
    16     }
    17 
    18 
    19     @Test
    20     void startAndEnd() {
    21         Map<String, String> map = Maps.newHashMap();
    22         map.put("startsWith", "e");
    23         map.put("endsWith", "e");
    24         Assertions.assertEquals(1, dictClient.startAndEnd(map).size());
    25     }
    26 
    27     @Test
    28     void replace() {
    29         Assertions.assertNotEquals(dictClient.replace(Collections.singletonMap("bike", "bikes")).indexOf("bikes"), -1);
    30     }
    31 
    32     @Test
    33     void updateFirst() {
    34         Assertions.assertEquals("game", dictClient.updateFirst("game").get(0));
    35     }
    36 
    37     @Test
    38     void deleteFirst() {
    39         Assertions.assertEquals(13, dictClient.deleteFirst().size());
    40     }
    41 
    42 
    43     @Test
    44     void headers() {
    45         Map<String, Object> headers = Maps.newHashMap();
    46         headers.put("age", 15);
    47         headers.put("length", 21);
    48         Assertions.assertTrue(dictClient.headers(headers).containsKey("age"));
    49         Assertions.assertTrue(dictClient.headers(headers).containsKey("length"));
    50     }
    51 
    52     @Test
    53     void add() {
    54         String var1 = "go~";
    55         String var2 = "back";
    56         List<String> adds = dictClient.add(Maps.toMap(Arrays.asList(var1, var2), input -> input));
    57         Assertions.assertTrue(adds.contains(var1));
    58         Assertions.assertTrue(adds.contains(var2));
    59 
    60     }
    61 }

    2.3 改写登录流程

    2.3.1 配置 FormEncoder

    由于使用 Spring 默认使用 Jackson(Json) ,我们需要手动配置一个 FormEncoder,需要注意的是配置类不能写成 Component 以避免自动配置的 encoder 被替换;

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 public class LoginClientConfig {
     6     @Bean
     7     public FormEncoder formEncoder() {
     8         return new FormEncoder(new JacksonEncoder());
     9     }
    10 }

    2.3.2 编写 LoginClient

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 @FeignClient(name = "loginClient", url = "127.0.0.1:8080", configuration = LoginClientConfig.class)
     6 public interface LoginClient {
     7     /**
     8      * @see LoginController#loginWithJson
     9      */
    10     @PostMapping(value = "login", consumes = MediaType.APPLICATION_JSON_VALUE)
    11     Response loginWithJson(@RequestBody UserInfo userInfo);
    12 
    13     /**
    14      * @see LoginController#loginWithForm
    15      */
    16     @PostMapping(value = "login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    17     Response loginWithForm(UserInfo userInfo);
    18 
    19 
    20     /**
    21      * @see LoginController#loginWithToken
    22      */
    23     @PostMapping("login")
    24     Response loginWithToken(@RequestHeader("Authorization") String token);
    25 
    26 
    27 }

    2.3.3 编写测试

     1 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
     2 class LoginClientTest {
     3 
     4     @Autowired
     5     private LoginClient loginClient;
     6 
     7     @Test
     8     void loginWithJson() {
     9         Response res = loginClient.loginWithJson(new UserInfo().setPassword("root").setUsername("admin"));
    10         Assertions.assertEquals(200, res.getStatus());
    11     }
    12 
    13     @Test
    14     void loginWithForm() {
    15         Response res = loginClient.loginWithForm(new UserInfo().setPassword("root").setUsername("admin"));
    16         Assertions.assertEquals(200, res.getStatus());
    17     }
    18 
    19     @Test
    20     void loginWithToken() {
    21         Response res = loginClient.loginWithToken("Bearer user-token");
    22         Assertions.assertEquals(200, res.getStatus());
    23     }
    24 
    25 }

    3. 代理

    代理的使用总是不可避免地,就像怕配置 encoder 一样,让我们为 GitHubClient 配置一个代理

    3.1 代理配置类

    参照 feign 的基本使用与 2.3.1,我们可以很快的写配置类,同样避免将配置类写成 Component

     1 /**
     2  * @author pancc
     3  * @version 1.0
     4  */
     5 public class GitHubClientConfig {
     6     @Bean
     7     public Client client() {
     8         okhttp3.OkHttpClient okHttpClient =
     9                 new okhttp3.OkHttpClient.Builder().proxy(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 10808))).build();
    10         return new OkHttpClient(okHttpClient);
    11     }
    12 }

    3.2 修改 GithubClient 配置

    1 @FeignClient(name = "gitHubs", url = "https://api.github.com", qualifier = "gitHubsClient", configuration = GitHubClientConfig.class)
    2 public interface GitHubClient {
    3 ....

    4. 总结要点

    4.1 依赖

         <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter</artifactId>
            </dependency>
     <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR3</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>

    4.2 编写方式

    1. 启动注解 @EnableFeignClients
    2. feign 接口使用 @FeignClient 注解
    3. feign 接口使用 SpringMVC 风格
    4. feign 的配置写在一个不被 Spring 实例化的配置类中,各种 feign 基本模块写成 Bean。启用时只添加配置类进相应的 feign 接口的注解字段中
    5. 使表单需要配置 FormEncoder
    6. feign 接口方法的第一个参数可以为 URI ,用于动态替换 FeignClient 中的 url 

     

     

  • 相关阅读:
    设计模式:备忘录模式??
    jQuery总结
    MYSQL(三)
    MYSQL(二)
    MYSQL(一)
    Web.xml配置详解
    Spring-JDBC通用Dao
    网络七层协议的形象说明
    网络编程概念
    JSP 9 大内置对象详解
  • 原文地址:https://www.cnblogs.com/siweipancc/p/12637083.html
Copyright © 2011-2022 走看看