SpringCloud最新版环境集成之feign

前言

本文依托于

在SpringCloud的使用过程中我总结为三步曲。

  • 引入spring-cloud-starter相应jar包
  • properties或yml加入相关配置
  • 启动类加上@Enable相关注解

eureka客户端

使用feign,需要先将自己注册在eureka,同时从eureka拉取服务名。

1.引入jar

以前的版本是引入spring-cloud-starter-eureka.jar,最新版引入spring-cloud-starter-netflix-eureka-client.jar

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>gson</artifactId>
            <groupId>com.google.code.gson</groupId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
 	 <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.10.5.1</version>
</dependency>
2.properties加入配置
eureka.client.serviceUrl.defaultZone=http://localhost:10001/eureka/,http://localhost:10002/eureka/

eureka.instance.prefer-ip-address=true
3.启动类加入注解
@EnableDiscoveryClient

feign客户端

1.引入jar
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.properties加入配置

无必需配置

3.启动类加入注解
@EnableFeignClients
4.增加feign接口

name或value配置服务提供者在eureka注册的名称,则该接口可以被注入并调用服务提供者的接口

@FeignClient(name= "springcloud-producer")
public interface HelloFeign {
    @RequestMapping(value = "/hello")
    String hello();
}

问题

1.启动报jackson-databind相关错误
java.lang.NoClassDefFoundError: com/fasterxml/jackson/annotation/JsonKey
	at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.hasAsKey(JacksonAnnotationIntrospector.java:1080) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:495) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:421) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueAccessor(POJOPropertiesCollector.java:270) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueAccessor(BasicBeanDescription.java:258) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:391) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:220) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:169) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1473) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1421) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.SerializerProvider._findExplicitUntypedSerializer(SerializerProvider.java:1390) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.hasSerializerFor(DefaultSerializerProvider.java:260) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.ObjectMapper.canSerialize(ObjectMapper.java:3350) ~[jackson-databind-2.12.5.jar:2.12.5]
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canWrite(AbstractJackson2HttpMessageConverter.java:274) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.http.converter.AbstractGenericHttpMessageConverter.canWrite(AbstractGenericHttpMessageConverter.java:76) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:977) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:774) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:602) ~[spring-web-5.3.12.jar:5.3.12]
	at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.register(RestTemplateEurekaHttpClient.java:77) ~[spring-cloud-netflix-eureka-client-3.0.4.jar:3.0.4]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.execute(RedirectingEurekaHttpClient.java:91) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:120) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:876) ~[eureka-client-1.10.16.jar:1.10.16]
	at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:121) ~[eureka-client-1.10.16.jar:1.10.16]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_251]
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_251]
	at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_251]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_251]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_251]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_251]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_251]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_251]

上述问题是因为jackson-databind版本过高,不兼容导致的,通过引入低版本的jackson-databind.jar,排除高版本的jar解决。

<dependency>
 	 <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.10.5.1</version>
</dependency>
2.引入了eureka-client的jar,但是没有注册成功

看你引入的jar是否正确,我就引入错误,引入了spring-cloud-netflix-eureka-client.jar,这个jar名缺个starter,太坑了

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>

通过maven,可以看到该依赖没有引入任何其他的jar,包括eureka-client.jar这个核心jar也没有。
在这里插入图片描述
而观察spring-cloud-starter-netflix-eureka-client.jar,可以看到他是包含spring-cloud-netflix-eureka-client.jareureka-client.jar等jar包
在这里插入图片描述
由此,如果你引入的是没有starter的jar,你还需要引入

<dependency>
    <groupId>com.netflix.eureka</groupId>
    <artifactId>eureka-client</artifactId>
    <version>1.10.16</version>
    <exclusions>
        <exclusion>
            <artifactId>gson</artifactId>
            <groupId>com.google.code.gson</groupId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

通过这种方式引入的不会有jackson-databind版本过高的问题。如果你有的话,排除版本高的jar。

3.上述配置都正确,服务提供者接口可以调通,但通过feign就是调不通

查看你的服务提供者是否有配置server.servlet.context-path,如下图所示
在这里插入图片描述
如果你配置了context-path,只参考其他人的文档你无法调通。
有两种方式解决:

  • 去除服务提供者的context-path配置
  • 在feign接口的位置@RequestMapping()中的url加上context-path的值,如下图所示
    在这里插入图片描述
4.多个feign接口,启动报错
Description:

The bean 'springcloud-producer.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

这是由于两个feign接口的value值设置的同一个值,调用的是同一个服务提供者,将方法合到一个接口或者按他的提示在properties加入如下配置。

spring.main.allow-bean-definition-overriding=true

版权声明:本文为qq_39217714原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。