无法让 Feign Client 为基本示例工作

新手上路,请多包涵

无法让 Feign Client 工作。首先尝试使用 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();
        }

    }
}

应用:

尝试了所有可能的注释排列,认为它可以解决 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);
    }
}

2016-07-20 18:15:42.406[0;39m [31mERROR[0;39m [35m32749[0;39m [2m—[0;39m [2m[主][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 在创建对象时抛出异常;嵌套异常是 java.lang.NullPointerException at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support .AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) [spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java: 482)[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory\(1.getObject(AbstractBeanFactory.java:306)~\[spring-beans- 4.2.6.RELEASE.jar:4.2.6.RELEASE\] 在 org.springframework.beans.fa ctory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~\[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE\] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory .java:302) ~\[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE\] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~\[spring- beans-4.2.6.RELEASE.jar:4.2.6.RELEASE\] 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~\[spring-beans-4.2.6.RELEASE.jar :4.2.6.RELEASE\] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~\[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE\] at org.springframework .context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~\[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE\] at org.springframework.bo ot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~\[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE\] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java :766) \[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE\] 在 org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361) \[spring-boot-1.3.5.RELEASE。 jar:1.3.5.RELEASE\] 在 org.springframework.boot.SpringApplication.run(SpringApplication.java:307) \[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE\] 在 org.springframework.boot .SpringApplication.run(SpringApplication.java:1191) \[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE\] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) \[spring- boot-1.3.5.RELEASE.jar:1.3.5.RELEASE\] 在 com.paa.ServiceApplication.main(ServiceApplication.java:44) \[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.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory .annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] … 17 com.n 帧省略

原文由 Rockoder 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 557
1 个回答

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

  1. 您应该尽量不要使用 url 属性。相反,使用 <feign client name>.ribbon.listOfServersbootstrap.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

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

  1. 您可能已经注意到我在 curl 请求中指定了一个 User-Agent 标头。那是因为 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"
    }
}

假装客户端

 @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();
}

启动应用程序

 @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();
        }
    }
}

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

集成测试

 @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));
    }
}

原文由 Abhijit Sarkar 发布,翻译遵循 CC BY-SA 3.0 许可协议