在同一个项目中配置spring cloud合约和zuul代理

Posted

技术标签:

【中文标题】在同一个项目中配置spring cloud合约和zuul代理【英文标题】:Configure spring cloud contract and Zuul proxy in the same project 【发布时间】:2017-01-31 06:18:03 【问题描述】:

我在消费者端将 spring-cloud-contract 与我的服务集成时遇到了问题。在我的服务中,我使用了 spring-cloud 中的已经 feign(调用其他服务)和 zuul(用于路由)。当我尝试运行使用 @AutoConfigureStubRunner 注释的测试时,就会出现问题。这是我的简单课程:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = "group:artifact:+:stubs:8080", workOffline = true)
public class WithContractTests 
    @Test
    public void test() 

在输出中我可以看到存根已正确启动:

o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts=group:artifact:1.0.0-SNAPSHOT:stubs=8080]

然后在创建 spring 上下文时出现此错误:

Caused by: java.lang.UnsupportedOperationException: null
at java.util.AbstractList.add(AbstractList.java:148) ~[na:1.8.0_91]
at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_91]
at java.util.AbstractCollection.addAll(AbstractCollection.java:344) ~[na:1.8.0_91]
at org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerDiscoveryClient.getServices(StubRunnerDiscoveryClient.java:139) ~[spring-cloud-contract-stub-runner-1.0.0.RC1.jar:1.0.0.RC1]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.locateRoutes(DiscoveryClientRouteLocator.java:105) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.locateRoutes(DiscoveryClientRouteLocator.java:43) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator.doRefresh(SimpleRouteLocator.java:152) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.refresh(DiscoveryClientRouteLocator.java:155) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping.setDirty(ZuulHandlerMapping.java:61) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.zuul.ZuulConfiguration$ZuulRefreshListener.onApplicationEvent(ZuulConfiguration.java:180) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:166) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:382) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:388) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:336) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:877) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:110) ~[spring-cloud-context-1.1.2.RELEASE.jar:1.1.2.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:79) ~[spring-cloud-context-1.1.2.RELEASE.jar:1.1.2.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:115) ~[spring-cloud-context-1.1.2.RELEASE.jar:1.1.2.RELEASE]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.getOptional(FeignClientFactoryBean.java:139) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.feign(FeignClientFactoryBean.java:84) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:157) ~[spring-cloud-netflix-core-1.2.0.RC1.jar:1.2.0.RC1]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]

有趣的是,在 spring-cloud-contract 示例中也出现了同样的错误: https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/standalone/dsl/http-client 将 Zuul 添加到项目后。通过添加 Zuul,我的意思是添加 spring-cloud-starter-zuul 作为依赖项和 @EnableZuulProxy 注释。之后我们在执行测试时可以看到如下错误:

java.lang.UnsupportedOperationException: null
at java.util.AbstractList.add(AbstractList.java:148) ~[na:1.8.0_91]
at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_91]
at java.util.AbstractCollection.addAll(AbstractCollection.java:344) ~[na:1.8.0_91]
at org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerDiscoveryClient.getServices(StubRunnerDiscoveryClient.java:139) ~[spring-cloud-contract-stub-runner-1.0.0.BUILD-20160922.090756-647.jar:1.0.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.locateRoutes(DiscoveryClientRouteLocator.java:105) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.locateRoutes(DiscoveryClientRouteLocator.java:43) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator.doRefresh(SimpleRouteLocator.java:152) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator.refresh(DiscoveryClientRouteLocator.java:155) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping.setDirty(ZuulHandlerMapping.java:61) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.cloud.netflix.zuul.ZuulConfiguration$ZuulRefreshListener.onApplicationEvent(ZuulConfiguration.java:180) ~[spring-cloud-netflix-core-1.2.0.BUILD-20160922.110240-890.jar:1.2.0.BUILD-SNAPSHOT]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:166) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:382) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:336) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:877) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-1.4.0.BUILD-20160728.175440-591.jar:1.4.0.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369) ~[spring-boot-1.4.0.BUILD-20160728.175440-591.jar:1.4.0.BUILD-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) ~[spring-boot-1.4.0.BUILD-20160728.175440-591.jar:1.4.0.BUILD-SNAPSHOT]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111) [spring-boot-test-1.4.0.BUILD-20160728.175440-528.jar:1.4.0.BUILD-SNAPSHOT]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) [junit-4.12.jar:4.12]
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) [junit-rt.jar:na]
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) [junit-rt.jar:na]
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253) [junit-rt.jar:na]
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) [junit-rt.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]

在使用 Zuul 和 Stub runner 时是否需要一些额外的配置?

【问题讨论】:

【参考方案1】:

天哪,这是我的错误。您可以在合同中提出问题吗?到现在为止,您必须做的是覆盖现有的类,该类不会将服务器添加到从委托返回的列表中,而是创建一个新的列表来添加服务器。我还没有针对 Zuul 进行过测试:/

这里已经修复(希望如此) - https://github.com/spring-cloud/spring-cloud-contract/issues/82

【讨论】:

好的,谢谢你的信息,我为 spring-cloud-contract 创建了一张票 问题确实得到了解决。非常感谢! 太棒了!您能将此问题标记为已回答吗?

以上是关于在同一个项目中配置spring cloud合约和zuul代理的主要内容,如果未能解决你的问题,请参考以下文章

如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url

spring cloud 合约 - Feign Clients

Spring Cloud 合约功能

Spring Cloud 入门教程 - 搭建配置中心服务

使用Spring Cloud合约进行消费者驱动的合同测试

Spring Cloud 合约功能