katiex7
katiex7

Reputation: 913

Is Spring's @RefreshScope broken or am I using it wrong?

I have a Spring Config Server running with @EnableConfigServer and it's working fine

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

Then I also have the client, running with @SpringBootApplication and @RefreshScope

@SpringBootApplication
@RefreshScope
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

as well as my RestController

@RestController
@RefreshScope
public class LicenseServiceController {
   @Value("${some.property}")
   String someProperty;

   @GetMapping("/someProperty")
   public String getSomeProperty() {
      return someProperty;
   }
}

Now, I've made Config Server talk to my private github repo endpoint to retrieve configuration properties and it does just that perfectly fine, for example if I hit my endpoint http://localhost:8888/y/default, it would give me back this snippet

propertySources: [
{
      name: "https://github.com/me/config/x/y.yml",
      source: {
         some.property: "hi"
      }
}
]

It all works fine, and when I hit the endpoint that uses the property by @Value tag, from the client side, I get back hi for @Value(${some.property})

The problem is when I update my git repo and change the some.property to "bye". If I hit the endpoint again from the client side, I will get back "hi" again for @Value(${some.property}) instead of "bye".

In the config server endpoint http://localhost:8888/y/default, I then get

propertySources: [
{
      name: "https://github.com/me/config/x/y.yml",
      source: {
         some.property: "bye"
      }
}
]

While in the client side, I still get "hi" for @Value(${some.property}) even if I hit the /actuators/refresh endpoint from the client side using a POST request

This is the debug log I get from the client side(SpringBootApplication) which seems to me like the POST request worked, I get the proper response from my curl command as well, at least I think

 INFO 13493 --- [nio-8080-exec-2] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$b4dd7d61] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
 INFO 13493 --- [nio-8080-exec-2] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888 
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.client.RestTemplate              : Created GET request for "http://localhost:8888/y/default"
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.client.RestTemplate              : Setting request Accept header to [application/json, application/*+json]
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.client.RestTemplate              : GET request for "http://localhost:8888/y/default" resulted in 200 (null)
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.client.RestTemplate              : Reading [class org.springframework.cloud.config.environment.Environment] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@2e68f713]
 INFO 13493 --- [nio-8080-exec-2] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=y, profiles=[default], label=null, version=948c431771g06325k3520x67k70z74xa2829ts33, state=null
 INFO 13493 --- [nio-8080-exec-2] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='configService', propertySources=[MapPropertySource {name='configClient'}, MapPropertySource {name='https://github.com/me/tmp-config/x/y.yml'}]}
 INFO 13493 --- [nio-8080-exec-2] o.s.boot.SpringApplication               : The following profiles are active: default
 INFO 13493 --- [nio-8080-exec-2] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@6a81dcff: startup date [Fri Jul 13 21:02:29 EDT 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@7ab876b9
 INFO 13493 --- [nio-8080-exec-2] o.s.boot.SpringApplication               : Started application in 0.202 seconds (JVM running for 24.359)
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'bootstrapProperties' with 'bootstrapProperties' 
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'random' with 'random'
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'applicationConfig: [classpath:/application.yml]' with 'applicationConfig: [classpath:/application.yml]'
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'springCloudClientHostInfo' with 'springCloudClientHostInfo'
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'applicationConfig: [classpath:/bootstrap.yml]' with 'applicationConfig: [classpath:/bootstrap.yml]'
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'defaultProperties' with 'defaultProperties
DEBUG 13493 --- [nio-8080-exec-2] o.s.w.c.s.StandardServletEnvironment     : Replacing PropertySource 'defaultProperties' with 'defaultProperties'
 INFO 13493 --- [nio-8080-exec-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6a81dcff: startup date [Fri Jul 13 21:02:29 EDT 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@7ab876b9
 INFO 13493 --- [nio-8080-exec-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7ab876b9: startup date [Fri Jul 13 21:02:29 EDT 2018]; root of context hierarchy
DEBUG 13493 --- [nio-8080-exec-2] m.m.a.RequestResponseBodyMethodProcessor : Written [[config.client.version, some.property]] as "application/vnd.spring-boot.actuator.v2+json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@67770b37]
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
DEBUG 13493 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Successfully completed request

Now, the only conclusion I can come up with is that the endpoint url is wrong because in the log it says "https://github.com/me/config/x/y.yml"

but in the browser that gives a 404, because it should be "https://github.com/me/config/blob/master/x/y.yml" instead, but that seems like a unlikely bug from the Spring writers. Seems like I did everything right, but somehow it's still broken

Upvotes: 1

Views: 6050

Answers (1)

Darren Forsythe
Darren Forsythe

Reputation: 11411

You should be refreshing beans not trying to refresh the entire application, and all the configurations > beans that it loads.

From the Spring docs,

https://cloud.spring.io/spring-cloud-static/docs/1.0.x/spring-cloud.html#_refresh_scope

@RefreshScope works (technically) on an @Configuration class, but it might lead to surprising behaviour: e.g. it does not mean that all the @Beans defined in that class are themselves @RefreshScope. Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in @RefreshScope (in which it will be rebuilt on a refresh and its dependencies re-injected, at which point they will be re-initialized from the refreshed @Configuration).

What you should do is refresh the bean wherever the value is being injected into.

Upvotes: 1

Related Questions