如何在 Spring-Cloud 中将 ConsulDiscoveryClient 与 Zuul 和 Sidecar 一起使用
Posted
技术标签:
【中文标题】如何在 Spring-Cloud 中将 ConsulDiscoveryClient 与 Zuul 和 Sidecar 一起使用【英文标题】:How do I use the ConsulDiscoveryClient with Zuul and Sidecar in Spring-Cloud 【发布时间】:2015-12-13 02:41:09 【问题描述】:我正在尝试将 Spring-Cloud 微服务架构与来自 Netflix 的 Sidecar 和 Zuul 组件一起使用 an example from kbastani on github
将部署服务的环境已经有一个正在运行的 consul 服务,可以用于服务发现和配置。这应该意味着我可以从示例中消除 config-service 和 eureka。
我现在正在尝试使用以下代码将 api-gateway 微服务连接到 Consul:
@SpringBootApplication
@EnableSidecar
@EnableDiscoveryClient
public class GatewayApplication
@Autowired
@Qualifier("consulDiscoveryClient")
DiscoveryClient discovery;
public static void main(String[] args)
SpringApplication.run(GatewayApplication.class, args);
这会导致以下异常:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gatewayApplication.MyZuulProxyConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.cloud.client.discovery.DiscoveryClient org.springframework.cloud.netflix.zuul.ZuulProxyConfiguration.discovery; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.cloud.client.discovery.DiscoveryClient] is defined: expected single matching bean but found 2: consulDiscoveryClient,discoveryClient
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201)
at org.springframework.boot.context.embedded.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:209)
at org.springframework.boot.context.embedded.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:85)
at org.springframework.boot.context.embedded.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:73)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getServletContextInitializerBeans(EmbeddedWebApplicationContext.java:234)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.selfInitialize(EmbeddedWebApplicationContext.java:221)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.access$000(EmbeddedWebApplicationContext.java:84)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:206)
at org.springframework.boot.context.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:54)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5156)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
... 1 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.cloud.client.discovery.DiscoveryClient org.springframework.cloud.netflix.zuul.ZuulProxyConfiguration.discovery; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.cloud.client.discovery.DiscoveryClient] is defined: expected single matching bean but found 2: consulDiscoveryClient,discoveryClient
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 32 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.cloud.client.discovery.DiscoveryClient] is defined: expected single matching bean but found 2: consulDiscoveryClient,discoveryClient
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1079)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
... 34 more
这个服务的 pom.xml 是:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>api-gateway-microservice</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>nl.quby.nxt</groupId>
<artifactId>springCloudSpike</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-sidecar</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
bootstrap.yml:
spring:
application:
name: gateway
cloud:
consul:
host: consul
port: 8500
config:
enabled: true
encrypt:
failOnError: false
application.yml:
server:
port: 10000
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
谁能阐明我如何将 Spring Cloud 与 Consul 一起用作发现和配置服务来创建 API 网关?
【问题讨论】:
为什么要与 consul 一起使用 sidecar? Sidecar 存在的原因是 eureka 是基于 JVM 的。由于 consul 不是,它本身就是一个边车。 感谢您的反应。我的错误,我的印象是 Sidecar 是 API-Gateway 的必要部分。实际上 Zuul 就是这样。 【参考方案1】:你应该使用@EnalbeZuulProxy
,sidecar 用于非 java 服务作为服务发现客户端。 @EnalbeZuulProxy
还将为您启用发现客户端。
此外,您的错误清楚地表明您正在尝试通过接口自动连接DiscoveryClient
,并且您的上下文中已经有两个。一个是 spring-boot 自动配置,另一个是您创建的。
您不应该自己创建客户端,因为如果您的类路径上有适当的依赖项,自动配置将为您完成。
工作领事客户示例:
https://github.com/spring-cloud/spring-cloud-consul/tree/master/spring-cloud-consul-sample
【讨论】:
非常感谢您的回答。使用@EnableZuulProxy
而不是自己尝试连接 DiscoveryClient 确实完成了这项工作。尝试自己连接它是对 Spring Cloud 无法选择自身的反应。我还删除了 @EnableSidecar
注释和 Sidecar 作为上面@spencergibb 建议的依赖项。以上是关于如何在 Spring-Cloud 中将 ConsulDiscoveryClient 与 Zuul 和 Sidecar 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
不正确的字符串值:列的“\\xA0Consu ...”即使列具有 utf8mb4 编码
如何保证 spring-boot 和 spring-cloud版本一致