Не удается заставить 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 [main] [0; 39m [36mo.s.boot] .SpringApplication [0; 39 мин. [2 мин.: [0; 39 мин. Ошибка при запуске приложения

Я не уверен, что вы в конце концов поняли это сами, но для тех, кто может наткнуться на эту ветку, ниже приведен рабочий пример того, что вы пытались сделать. Сначала я укажу на несколько вещей, которые неверны или, по крайней мере, нежелательны в вашем коде, а затем покажу свой работающий код.


person Rockoder    schedule 21.07.2016    source источник


Ответы (3)


При тестировании с использованием curl я обнаружил, что Reddit отвечает очень долго. См. Это SO сообщение для получения подробной информации о том, как разбить общее время, затрачиваемое на цикл запрос-ответ.

  1. Используя ленту для HTTPS-соединений, вам нужно указать две вещи, которые вам не нужны для HTTP-соединений. Порт, входящий в состав listOfServers и <feign client name>.ribbon.IsSecure: true. Без порта соединение устанавливается на порт 80, а без IsSecure используется HTTP.
  2. Вы могли заметить, что я указал заголовок User-Agent в запросе curl. Это потому, что Reddis кажется очень разборчивым в этом вопросе и, если не указано иное, в большинстве случаев возвращает HTTP 429 «Слишком много запросов». Они не возвращают заголовок Retry-After в ответе, поэтому нельзя сказать, сколько времени вам нужно ждать, прежде чем сделать следующий запрос.
  3. Согласно Wiki Netflix тайм-ауты чтения и подключения по умолчанию составляют 3000 миллисекунд, поэтому у вас всегда будет тайм-аут, если вы их не измените.

    $ 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
    

«Говорить дешево. Покажи код». (Торвальдс, Линус (25 августа 2000 г.)).

  1. Spring Cloud Netflix, как и Netflix Feign, имеют открытый исходный код, поэтому немного (много) терпения и навыков отладки действительно пригодятся.
  2. Зависимости:

Я создал приложение Gradle, используя отличный сайт Spring Initializr. Вот отрывок из 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();
}

bootstrap.yml:

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

Интеграционный тест:

reddit:
  ribbon:
    listOfServers: www.reddit.com:443
    ConnectTimeout: 20000
    ReadTimeout: 20000
    IsSecure: true
hystrix.command.default.execution:
  timeout.enabled: true
  isolation.thread.timeoutInMilliseconds: 50000

Вам следует постараться не использовать атрибут url. Вместо этого настройте список серверов, используя <feign client name>.ribbon.listOfServers в bootstrap.yml (или bootstrap.properties). Это позволяет балансировать нагрузку на стороне клиента, поскольку listOfServers может быть списком, разделенным запятыми.

@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));
    }
}
person Abhijit Sarkar    schedule 13.12.2016
comment
Я попытался уточнить, что мы использовали Feign без ленты. Таким образом, Ribbon не является обязательным для использования Feign ==== feign: hystrix: enabled: false источник данных: audit: mongodb: host: localhost port: 27019 database: audit === - person Rockoder; 27.01.2017
comment
@Rockoder Вы смогли выполнить эту работу. У вас есть образец кода? - person Rockoder; 28.01.2017
comment
@alltej да смог заставить его работать, хотя получить код было бы немного сложно. По сути, мы создали родительский модуль, служащий нашим фреймворком, и использовали там Feign. Модулю, который использовал Feign, не нужно было явно объявлять Feign в дочерних классах. Также важен весенний вариант. Мы были на 3.5. Я узнал от коллеги, когда они пытались использовать более позднюю версию, у них возникли проблемы, и они в конечном итоге вернулись к версии, которую мы использовали, чтобы заставить ее работать. - person alltej; 01.05.2017
comment
Комментарии @alltej имеют ограничение, поэтому я отправил вам ответ. Надеюсь, это поможет. Все основные компоненты / классы, необходимые для работы, есть. Сообщите мне, если это сработает. Кроме того, версия 3.5, о которой я упоминал выше, была ошибочной. Это 1.3.5. - person Rockoder; 12.05.2017
comment
org.springframework.beans.factory.BeanCreationException: ошибка создания bean-компонента с именем testWLCController: не удалось ввести автоматически подключенные зависимости; вложенное исключение - org.springframework.beans.factory.BeanCreationException: не удалось автоматически подключить поле: private com.paa.controllers.GetFeignClient com.paa.controllers.TestWLCController.gfClient; вложенное исключение - org.springframework.beans.factory.BeanCreationException: Ошибка создания bean-компонента с именем 'com.aa..controllers.GetFeignClient': FactoryBean выдал исключение при создании объекта; вложенное исключение - это исключение java.lang.NullPointerException в org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues ​​(AutowiredAnnotationBeanPostProcessor.java:334) ~ [Spring-beans. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean (AbstractAutowireCapableBeanFactory.java:1214) ~ [spring-beans-4.2.6.RELEASE.jar: 4.2.6.RELEASE.fctory.support.factory.support] в orfag.springbean. .AbstractAutowireCapableBeanFactory.doCreateBean (AbstractAutowireCapableBeanFactory.java:543) ~ [spring-beans-4.2.6.RELEASE.jar: 4.2.6.RELEASE] в org.springframework.beansuto.factory. 482) ~ [spring-beans-4.2.6.RELEASE.jar: 4.2.6.RELEASE] в 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.factory.support.DefaultSingletonBeanRegistry.getSingleton (DefaultSingletonBeanRegistry.java:230) ~ [spring-beans-4.2.6.RELEASE.jar: 4.2.6.RELEASE] в org.springframework.beans.fa .support.AbstractBeanFactory.doGetBean (AbstractBeanFactory.java:302) ~ [spring-beans-4.2.6.RELEASE.jar: 4.2.6.RELEASE] в org.springframework.beans.factory.support.AbstractBeanFactory.getBeanFactory (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] в org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization (AbstractApplicationContext.java:839) ~ [spring-context-4.2.6.RELEASE.jar: 4.2. 6.RELEASE] на org.springframework.context.support. AbstractApplicationContext.refresh (AbstractApplicationContext.java:538) ~ [spring-context-4.2.6.RELEASE.jar: 4.2.6.RELEASE] в org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh (EmbeddedWebApplicationContext.java ) ~ [spring-boot-1.3.5.RELEASE.jar: 1.3.5.RELEASE] в 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] в org.springframework.boot.SpringApplication.run (SpringApplication.java:1180) [spring-boot-1.3.5.RELEASE.jar: 1.3.5.RELEASE ] на ком. paa.ServiceApplication.main (ServiceApplication.java:44) [bin /: na] Вызвано: org.springframework.beans.factory.BeanCreationException: не удалось автоматически подключить поле: private com.paa.controllers.GetFeignClient com.paa.controllers. TestWLCController.gfClient; вложенное исключение - org.springframework.beans.factory.BeanCreationException: Ошибка создания bean-компонента с именем com.paa.controllers.GetFeignClient: FactoryBean выдал исключение при создании объекта; вложенное исключение - это исключение java.lang.NullPointerException в org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $ AutowiredFieldElement.inject (AutowiredAnnotationBeanPostProcessor.java: 4.2.6. ] в 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 пропущены - person Rockoder; 12.05.2017

Приложение:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

         <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-parent</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

Кому-то было интересно узнать, как мы это сделали, поэтому разместили ответ в их интересах.

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.test.cloud.bookservice.models.Book;

@SpringBootApplication
@RestController
@RequestMapping("/books")
@EnableFeignClients
public class BookServiceApplication {

    Logger logger = LogManager.getLogger(BookServiceApplication.class);

    @Autowired
    private StoreClient storeClient;


    public static void main(String[] args) {
        SpringApplication.run(BookServiceApplication.class, args);
    }


    @GetMapping("/book")
    public Book findBook() {
            return this.restTemplate.getForObject("http://stores/book", Book.class);
    }

    @FeignClient(name = "StoreClient", url = "127.0.0.1:8089")
    interface StoreClient {
        @RequestMapping(method = RequestMethod.GET, value = "/stores/book", consumes = "application/json")
        Book getBook();
    }

}
person Prasobh.Kollattu    schedule 05.07.2019

bootstrap.yml

Дочерний модуль

package com.hitech.module.base;

@EnableFeignClients
public abstract class BaseApplication extends SpringBootServletInitializer {
...
..
}

build.gradle:

buildscript {
    ext {
        springBootVersion = '1.3.5.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE")
    }
}
...
...

dependencies {
    compile('io.springfox:springfox-swagger-ui:2.5.0')
    compile('io.springfox:springfox-swagger2:2.5.0')
    compile('org.springframework.cloud:spring-cloud-starter-feign')

Мне удалось успешно использовать Feign, хотя на самом деле мы не использовали «ленту». Мы использовали как Rest Client, так как он намного чище. Другой урок, который мы усвоили, заключался в том, что для обработки заголовков и перехвата ответов в Feign необходимо реализовать декодеры для Feign, а также иметь конфигурацию Feign. Я отправлю код, как только у меня будет время.

package com.hitech.module.app;

import com.hitech.module.base.BaseApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication(exclude = {MongoDataAutoConfiguration.class, MongoAutoConfiguration.class},
        scanBasePackages = {"com.hitech.module.base", "com.hitech.module.app", })
@EnableFeignClients("com.hitech.module.app.clients")
public class MyServiceApplication extends BaseApplication {

    private static final Logger LOG = LoggerFactory.getLogger(MyServiceApplication.class);

    public static void main(String[] args) {

        String s1 = "google";

        LOG.info ("=== Started Orchestration Service ===");
        SpringApplication.run(MyServiceApplication.class, args);


    }
}

Родительский модуль

feign:
  hystrix:
    enabled: false
datasource:
  audit:
    mongodb:
      host: localhost
      port: 27019
      database: audit
person Rockoder    schedule 11.05.2017