前言
本文依托于
在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.jar和eureka-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