无法让Feign Client运行一个基本示例

Roc*_*der 5 rest spring-boot netflix-feign spring-cloud-feign feign

无法让Feign客户工作。首先尝试使用POST。保持与编码器/解码器有关的错误,指出类型不正确。然后在github上找到一个示例来最终调用简单的GET API,并决定尝试一下。仍然失败

在Github和在线上,我看到Feign Client Spring-Cloud,OpenFeign,Netflix.feign的多个版本具有不同的版本。谁能形容一个最好的,稳定的Feign客户应该用于生产什么?

package com.paa.controllers;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient (name="test-service",url="https://www.reddit.com/r")
public interface GetFeignClient {

     @RequestMapping(method = RequestMethod.GET, value = "/java.json")
     public String posts();
}

Controller:

@RestController
@RequestMapping("/some/api")
public class TestWLCController {

  @Autowired
  private GetFeignClient getFeignClient;

  .. some stuff


    @RequestMapping(value="/postSomething",method = RequestMethod.POST)
    @ApiOperation(value = "Configures something",
            notes = "basic rest controller for testing feign")

    public ResponseEntity<SomeResponse> feignPost(
            UriComponentsBuilder builder,
            @ApiParam(name = "myRequest", 
            value = "request for configuring something", 
            required = true)
            @Valid @RequestBody SomeRequest someRequest) {

        String resp = null;
        try {
            resp = getFeignClient.posts();
        } catch (Exception er) {
            er.printStackTrace();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

应用:

尝试了所有可能的注释排列方式,认为它将解决AutoWire问题,但仍然失败

@Configuration
@ComponentScan
@EnableAutoConfiguration
//@EnableEurekaClient
@EnableFeignClients

//@SpringBootApplication
//@EnableFeignClients
//@EnableFeignClients(basePackages = {"com.paa.xenia.controllers", "com.paa.xenia.services"})
public class ServiceApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

        return application.sources(XeniaServiceApplication.class);
    }

    public static void main(String[] args) {

        SpringApplication.run(ServiceApplication.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

2016-07-20 18:15:42.406 [0; 39m [31mERROR [0; 39m [35m32749 [0; 39m [2m --- [0; 39m [2m [main]] [0; 39m [36mo.s.boot .SpringApplication [0; 39m [2m:[0; 39m应用程序启动失败

org.springframework.beans.factory.BeanCreationException:创建名称为'testWLCController'的bean时出错:自动连接依赖项的注入失败;嵌套的异常是org.springframework.beans.factory.BeanCreationException:无法自动连线字段:私有com.paa.controllers.GetFeignClient com.paa.controllers.TestWLCController.gfClient; 嵌套的异常是org.springframework.beans.factory.BeanCreationException:创建名称为'com.aa..controllers.GetFeignClient'的bean时出错:FactoryBean在对象创建时抛出了异常;嵌套的异常是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)〜[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]处的java.lang.NullPointerException org。在com.paa.ServiceApplication.main(ServiceApplication.java:44)处运行(SpringApplication.java:1180)[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] [bin /:na]由:org.springframework.beans.factory.BeanCreationException:无法自动连线字段:私有com.paa.controllers.GetFeignClient com.paa.controllers.TestWLCController.gfClient; 嵌套的异常是org.springframework.beans.factory.BeanCreationException:创建名称为'com.paa.controllers.GetFeignClient'的bean时出错:FactoryBean在对象创建时抛出了异常;嵌套的异常是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $ AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)上的java.lang.NullPointerException〜[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE ],网址为org.springframework.beans。

Abh*_*kar 4

我不确定您最终是否自己弄清楚了,但为了其他可能偶然发现此线程的人,下面是您尝试执行的操作的示例。我将首先指出代码中不正确或至少不需要的一些内容,然后展示我的代码是否有效。

  1. 您应该尽量不要使用该url属性。<feign client name>.ribbon.listOfServers相反,请使用in bootstrap.yml(或)设置服务器列表bootstrap.properties。这允许客户端负载平衡,因为listOfServers可以是逗号分隔的列表。
  2. 使用 Ribbon 进行 HTTPS 连接时,您需要指定 HTTP 连接不需要的两件事。端口,是listOfServers和的一部分<feign client name>.ribbon.IsSecure: true。如果没有该端口,则将连接到端口 80;如果没有该端口IsSecure,则使用 HTTP。
  3. 使用 进行测试curl,我发现 Reddit 需要长时间才能响应。有关如何分解请求-响应周期所花费的总时间的详细信息,请参阅此 SO帖子。

    $ curl -v -H "User-Agent: Mozilla/5.0" -w "@curl-format.txt" -o /dev/null -s "https://www.reddit.com/r/java/top.json?count=1"
    { [2759 bytes data]
    * Connection #0 to host www.reddit.com left intact
    time_namelookup:     0.527
    time_connect:        0.577
    time_appconnect:     0.758
    time_pretransfer:    0.758
    time_redirect:       0.000
    time_starttransfer: 11.189
                      ----------
    time_total:         11.218
    
    Run Code Online (Sandbox Code Playgroud)

根据 Netflix Wiki,默认的读取和连接超时为 3000 毫秒,因此除非您更改这些设置,否则您将始终超时。

  1. 您可能已经注意到我User-Agentcurl请求中指定了标头。这是因为 Reddis 似乎对此非常挑剔,如果未指定,大多数时候都会返回 HTTP 429“请求过多”。它们不会Retry-After在响应中返回标头,因此无法告诉您在发出另一个请求之前需要等待多长时间。
  2. Spring Cloud Netflix 和 Netflix Feign 都是开源的,因此一些(大量)耐心和调试技巧非常有用。

“空谈是廉价的。给我看看代码。” (莱纳斯·托瓦兹 (2000-08-25))

我使用优秀的Spring Initializr站点生成了一个 Gradle 应用程序。这是该文件的一个片段build.gradle

dependencies {
    compile('org.springframework.cloud:spring-cloud-starter-feign')
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.SR3"
    }
}
Run Code Online (Sandbox Code Playgroud)

假冒客户

@FeignClient(name = "reddit")
public interface RedditClient {
    @RequestMapping(method = GET, value = "/r/java/top.json?count=1",
            headers = {USER_AGENT + "=Mozilla/5.0", ACCEPT + "=" + APPLICATION_JSON_VALUE})
    public String posts();
}
Run Code Online (Sandbox Code Playgroud)

启动应用程序

@SpringBootApplication
@EnableFeignClients
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @RestController
    static class DemoController {
        @Autowired
        private RedditClient redditClient;

        @GetMapping("/posts")
        public String posts() {
            return redditClient.posts();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

bootstrap.yml

reddit:
  ribbon:
    listOfServers: www.reddit.com:443
    ConnectTimeout: 20000
    ReadTimeout: 20000
    IsSecure: true
hystrix.command.default.execution:
  timeout.enabled: true
  isolation.thread.timeoutInMilliseconds: 50000
Run Code Online (Sandbox Code Playgroud)

集成测试

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTest {
    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testGetPosts() {
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("/posts", String.class);

        HttpStatus statusCode = responseEntity.getStatusCode();
        assertThat(String.format("Actual status code: %d, reason: %s.",
                statusCode.value(), statusCode.getReasonPhrase()),
                statusCode.is2xxSuccessful(), equalTo(true));
    }
}
Run Code Online (Sandbox Code Playgroud)