I'm running a Spring Config Server and another Spring boot app that uses config server. I have a Feign-Client in my second app like this:
@FeignClient(url = "${myconfig.url}", name = "ConfigServerFeign",
configuration = {FeignConfig.class}, fallback = ConfigServerFeignFallback.class)
public interface ConfigServerFeign
{
@RequestMapping(value = "/test", method = RequestMethod.POST,
headers = {"Content-Type=application/json; charset=UTF-8"}, consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})
RequestModel test(@RequestBody RequestModel request);
}
and i have a config class for feign like this:
@Configuration
public class FeignConfig
{
@Value("${myconfig.header}")
private String authorization;
@Bean
public RequestInterceptor basicAuthRequestInterceptor()
{
return requestTemplate -> requestTemplate.header("Authorization", "Basic " + authorization);
}
}
i need to change ${myconfig.url} or ${myconfig.header} in runtime. i think i have two option, first one is using @RefreshScope on top of ConfigServerConfig that does not work, the second option is to use @RefreshScope on FeignConfig class that gives me this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.configclient.ConfigServerFeign': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: No Scope registered for scope name 'refresh'
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1634) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:254) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1316) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1282) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1101) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
... 19 common frames omitted
Caused by: java.lang.IllegalStateException: No Scope registered for scope name 'refresh'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:372) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:116) ~[spring-cloud-context-1.2.4.RELEASE.jar:1.2.4.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:85) ~[spring-cloud-context-1.2.4.RELEASE.jar:1.2.4.RELEASE]
at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:121) ~[spring-cloud-context-1.2.4.RELEASE.jar:1.2.4.RELEASE]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.get(FeignClientFactoryBean.java:127) ~[spring-cloud-netflix-core-1.3.5.RELEASE.jar:1.3.5.RELEASE]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.feign(FeignClientFactoryBean.java:84) ~[spring-cloud-netflix-core-1.3.5.RELEASE.jar:1.3.5.RELEASE]
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:155) ~[spring-cloud-netflix-core-1.3.5.RELEASE.jar:1.3.5.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
... 29 common frames omitted
how can i fix this ??? :-(
Comment From: spencergibb
I would use @CongurationProperties
instead of @Value
.
Comment From: susongyan
i face with this problem too, @FeignClient(name="balabala" , url = "${myconfig.url}") ; i want to refresh the "url" but @RefreshScope doesn't work
version Edgware.SR2
Comment From: ryanjbaxter
@minorpoet did you try @spencergibb's suggestion?
Comment From: susongyan
@ryanjbaxter i thought they are different scenes, config class annotated with @CongurationProperties or @value + @RefreshScope can be refreshed on the fly ,like ` @CongurationProperties(prefix="url") @Data public class UrlConfig{ private String shop; }
@RefreshScope @Data public class UrlConfig{ @Value("url.shop") private String shop; } ` both can be refreshed on the fly , but @Feignclient(name="balabala" , url = "${myconfig.url}") placeholder is in the annotation , i don't know how to mark it refreshable , or the inner HardCodedTarget refreshable or the proxy client refreshed ... etc
Comment From: ryanjbaxter
Please provide an app that reproduces the issue and we will take a look.
Comment From: susongyan
sorry be absent , it was Tomb-Sweeping Day in china, we got 3 days off
@ryanjbaxter
here is my demo show this case :
https://github.com/minorpoet/feignclient-url-not-refresh
Comment From: susongyan
any response ?
Comment From: ryanjbaxter
Can you please simplify your sample? All those components should not be needed based on the description of the problem.
Comment From: BastiOfBerlin
I think I stumbled into the same problem and prepared a quite simple example: https://github.com/BastiOfBerlin/feignclient-refreshscope-problem
I change the URL after the EmbeddedServletContainer has been initialized. In my real app, I need to access the (randomly selected) port number to change the url property. I then refresh the scope. Unfortunately, the FeignClient seems to be already initialized and does not get refreshed.
Comment From: spencergibb
@BastiOfBerlin wouldn't it be simpler to use ribbon in that case. The url field was never meant to be updated.
Comment From: BastiOfBerlin
In this demo, definitely.
But I have to implement sort of a loopback to the exact same microservice. Using client.api-url=${server.port}
in the config doesn't work either. So I came up with the idea of waiting until the servlet container came up and set the config value to '"http://localhost:" + localServerPort'
.
If ribbon could do that, I'd be happy, but have no idea on how to implement that.
I guess there's no way to re-initialize all or specific FeignClients?
Comment From: susongyan
but, lacking of these components spring cloud config with bus won't work
Comment From: ryanjbaxter
@minorpoet
but, lacking of these components spring cloud config with bus won't work
what does this mean?
Comment From: susongyan
i mean, i need git repo and mq to support notifying config changing event to spring cloud config consumer; if not using mq and bus, git repo is needed at least and refresh config consumer directly through {consumer-host}:{port}/refresh
Comment From: ryanjbaxter
@minorpoet not sure what those components have to do with the problem. As @spencergibb said the url
field is not meant to be refreshed. You can instead use Ribbon and set client.ribbon.listOfServers
. When that property is updated and a refresh is performed than the Feign client should use the new property.
Comment From: susongyan
but my target url is php server, not registered in eureka; while the config consumer is resigtered
Comment From: spencergibb
The example above uses a configured list, not eureka. If you want to change the URL dynamically, that's the way to do it
Comment From: spencergibb
There is a section in the docs about creating feign clients manually
Comment From: odedia
Thanks Spencer, I'll check it out!
So just to clarify - you do not see a way to refresh the name attribute via @RefreshScope (or other means), correct?
Comment From: spencergibb
No there is not.
Comment From: sj853
@minorpoet 我也有相同的疑问 兄弟你解决了吗
Comment From: fcjreed
Sorry to hijack the issue. I have a question that's related to this problem but has more to do with using refresh scope on the override beans we can provide in the configuration, e.g Logging.Level, Request.Options. You cannot put @RefreshScope on these beans either as logging level complains about the bean being final and request options gives the scope refresh not existing error. It just won't work because the config isn't being injected per say, it's just being passed as a constructor arg.
Does the provided solution of using the property "feign.client.config.feignName.readTimeout" apply dynamic values if changed in config server?
Comment From: susongyan
@sj853 没呢,github通知没注意~~ 现在才看到
Comment From: spring-projects-issues
Closing due to age of the question. If you would like us to look at this issue, please comment and we will look at re-opening the issue.
Comment From: cens7
I have same question. Two years passed, did this question solved?
Comment From: hoseinit
I am also looking forward for a way to refresh feign when url has been changed and it's in RefreshScope
Comment From: tbw777
its of current interests