无法让假装客户端为基本示例工作



无法让Feign客户端工作。首次尝试POST。不断遇到与编码器/解码器有关的错误,称类型不正确。然后在github上找到了一个调用简单GET API的例子,并决定尝试一下。仍然失败

在Github和网上,我看到了多个版本的Feign客户端Spring Cloud、OpenFeign、Netflix.foreign都有不同的版本。有人能描述一下在生产中应该使用的最好、稳定的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;39 m[35m32749[0];39米[2m--[0;39m[2m[min][0;39m[36mo.sboot.SpringApplication[0;39m[2m:[0;39米应用程序启动失败

org.springframework.beans.factory.BeanCreationException:错误正在创建名为"testWLCController"的bean:注入autowired依赖关系失败;嵌套异常为org.springframework.beans.factory.BeanCreationException:无法autowire字段:private com.paa.controllers.GetFeignClientcom.paa.controllers.TestWLCController.gfClient;嵌套异常为org.springframework.beans.factory.BeanCreationException:错误正在创建名为"com.aa..controllers.GetFeignClient"的bean:FactoryBean在创建对象时引发异常;嵌套异常为位于的java.lang.NullPointerExceptionorg.springframework.beans.factory.annotations.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnorationBeanPostProcess.java:334)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)~[spring-bans-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.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)~[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]com.paa.ServiceApplication.main(ServiceApplication.java:44)[bin/:na]由:org.springframework.beans.factory.BeanCreationException引起:无法自动连接字段:private com.paa.controllers.GetFeignClientcom.paa.controllers.TestWLCController.gfClient;嵌套异常为org.springframework.beans.factory.BeanCreationException:错误正在创建名为"com.paa.controllers.GetFeignClient"的bean:FactoryBean在创建对象时引发异常;嵌套异常为位于的java.lang.NullPointerExceptionorg.springframework.beans.factory.annotations.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnorationBeanPostProcesser.java:573)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)~[spring-bans-4.2.6.RELEASE.jar:4.2.6.RELEASE]org.springframework.beans.factory.annotations.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnorationBeanPostProcess.java:331)~[spring-beans-4.26.RELEASE.jar:4.2.6.RELEASE]。。。17帧省略

我不确定你是否最终自己解决了这个问题,但为了其他可能偶然发现这个线程的人,下面是你试图做的一个工作示例。我将首先指出一些不正确的地方,或者至少是你的代码中不需要的地方,然后展示我的代码。

  1. 您应该尽量不要使用url属性。相反,在bootstrap.yml(或bootstrap.properties)中使用<feign client name>.ribbon.listOfServers设置服务器列表。这允许客户端负载平衡,因为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都是开源的,所以一些(很多)耐心和调试技巧真的派上了用场

"谈话很便宜。给我看看代码。"(Torvalds,Linus(2000-08-25))

我使用优秀的Spring Initializer网站生成了一个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"
}
}

Feign客户端:

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

引导程序。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);

}
}

引导程序.yml

feign:
hystrix:
enabled: false
datasource:
audit:
mongodb:
host: localhost
port: 27019
database: audit

相关内容

  • 没有找到相关文章

最新更新