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 

     

     

  • 相关阅读:
    flock对文件锁定读写操作的问题 简单
    hdu 2899 Strange Fuction(二分)
    hdu 2199 Can you solve this equation? (二分)
    poj 3080 Blue Jeans (KMP)
    poj 2823 Sliding Window (单调队列)
    poj 2001 Shortest Prefixes (trie)
    poj 2503 Babelfish (trie)
    poj 1936 All in All
    hdu 3507 Print Article (DP, Monotone Queue)
    fzu 1894 志愿者选拔 (单调队列)
  • 原文地址:https://www.cnblogs.com/siweipancc/p/12637083.html
Copyright © 2011-2022 走看看