FeignClientを動作させることができません。最初に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; 39m [2m:[0; 39mアプリケーションの起動に失敗しました
org.springframework.beans.factory.BeanCreationException:「testWLCController」という名前のBeanの作成中にエラーが発生しました:自動配線された依存関係の挿入に失敗しました。ネストされた例外はorg.springframework.beans.factory.BeanCreationExceptionです:フィールドを自動配線できませんでした:private 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.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] at 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- org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.Java:772)のbeans-4.2.6.RELEASE.jar:4.2.6.RELEASE]〜[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] at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.Java:361)[spring-boot-1.3.5.RELEASE。 jar:1.3.5.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.Java:307)[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE] at 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] at com.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です:「com.paa.controllers.GetFeignClient」という名前のBeanの作成中にエラーが発生しました:FactoryBeanがオブジェクトの作成時に例外をスローしました。ネストされた例外は、org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $ AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:573)〜[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASEのJava.lang.NullPointerExceptionです。 ] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:88)〜[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] at org.springframework.beans.factory .annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:331)〜[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] ... 17com.nフレームが省略されています
最終的に自分で理解したかどうかはわかりませんが、このスレッドに出くわす可能性のある他の人のために、以下はあなたがやろうとしていたことの実用的な例です。最初に、コードで正しくない、または少なくとも望ましくないいくつかのことを指摘してから、機能するコードを示します。
url
属性は使用しないようにしてください。代わりに、<feign client name>.ribbon.listOfServers
(またはbootstrap.yml
)でbootstrap.properties
を使用してサーバーのリストを設定します。 listOfServers
はコンマ区切りのリストにすることができるため、これによりクライアント側の負荷分散が可能になります。listOfServers
および<feign client name>.ribbon.IsSecure: true
の一部であるポート。ポートがない場合、接続はポート80に行われ、IsSecure
がない場合、HTTPが使用されます。curl
を使用してテストしたところ、Redditが応答するのに非常に長い時間がかかることがわかりました。要求と応答のサイクルにかかる合計時間を分析する方法の詳細については、このSO post )を参照してください。
$ 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ミリ秒であるため、これらを変更しない限り、常にタイムアウトになります。
curl
リクエストでUser-Agent
ヘッダーを指定したことに気付いたかもしれません。これは、Reddisがそれについて非常にうるさいようであり、指定されていない場合、ほとんどの場合HTTP429「Toomanyrequests」を返すためです。応答でRetry-After
ヘッダーを返さないため、別のリクエストを行う前にどれだけ待つ必要があるかはわかりません。「話は安い。コードを見せて」 (トーバルズ、ライナス(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));
}
}
依存関係:
<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();
}
}
誰かが私たちがそれをどのように行ったかを知りたいと思ったので、彼らの利益のために答えを投稿しました。
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')
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);
}
}
bootstrap.yml
feign:
hystrix:
enabled: false
datasource:
audit:
mongodb:
Host: localhost
port: 27019
database: audit