spring-cloud / spring-cloud/spring-cloud-commons
RefreshScope dispose beans in unpredictable order
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 751
- Forks
- 744
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 9
Description
This issue was discovered while investigating https://github.com/spring-cloud/spring-cloud-netflix/issues/3174#issuecomment-419349960. To summarise the original tread:
When disposed, RefreshScope starts by clearing its local cache of target beans then proceeds with their disposal. A problem arise when one of these beans makes a call to another refresh-scoped bean in its dispose method - that is the case of Netflix's DiscoveryClient for instance. Since the cache has already been cleared, a new instance of the proxied reference must be created which leads to the BeanCreationNotAllowedException.
RefreshScope extends GenericScope whose shutdown method looks like this: https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-context/src/main/java/org/springframework/cloud/context/scope/GenericScope.java#L130-L134. As you can see it starts by clearing the local cache...
Furthermore, target beans are NOT disposed in an order that matches their dependencies. In fact, beans are disposed in the order they are returned by the StandardScopeCache which uses a ConcurrentHashMap underneath.
Changing the map implementation to preserve order will not be enough I'm afraid. Proxies are created in dependency order, but targets are created - and stored in the cache - when they are first invoked. To be 100% correct, the exact moment a target bean gets into the cache depends on:
RefreshScopeis configured with eager initialization (true by default). In this case, target beans are created onContextRefreshedEventin the order given bycontext.getBeanDefinitionNames()(does it reflect the dependency order?). Wheneager=false, target beans are created at the very last moment on their first use.- whether the bean definition is
@Lazyor not
A sample test app is available at https://github.com/brenuart/spring-cloud-commons/tree/netflix_gh3174 to illustrate the case. It is currently hosted in my own repo - please tell me if I should commit it elsewhere. You may not find all tests relevant - certainly in the light of the changes you foresee to solve this issue. Hope they will be useful anyway ;-)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the shutdown method in spring-cloud-context/src/main/java/org/springframework/cloud/context/scope/GenericScope.java and inspect how StandardScopeCache stores targets. Run or adapt the sample test app linked in the issue, including eager and lazy cases. Done means refresh-scoped beans dispose without BeanCreationNotAllowedException and in dependency-safe order.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, cloud
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100