Why Spring’s Bean Scanning Can Trigger Unresolvable Circular References (and How to Fix It)
This article examines how Spring Boot 2.0.3 resolves (or fails to resolve) setter‑based circular dependencies, explores bean definition scanning order, bean definition overriding, and instantiation sequence that can lead to an “unresolvable circular reference” error, and then shifts to explain ZGC’s mark‑compact algorithm, its evolution before and after JDK 16, and its performance characteristics.
Previous Review
Spring's circular dependency, detailed source analysis → Do we really need three‑level caches? The previous article explained that Spring can only solve setter‑based circular dependencies, not constructor‑based ones, and introduced how Spring resolves setter‑based circular dependencies.
First Exploration
Since Spring cannot solve constructor‑based circular dependencies, how does it identify them?
Second Exploration
From the source code perspective, Spring determines constructor‑based circular dependencies and prototype circular dependencies.
Project Simulation
After the first two explorations, the author thought they understood Spring's circular dependency issues, but could not spot the problem in a live environment.
SpringBoot version: 2.0.3.RELEASE
Online service deployed with Kubernetes; local environment not using Kubernetes.
Local startup never shows circular dependency; the online environment occasionally fails to start with a circular‑dependency error.
Simple project structure for troubleshooting.
Problem Reproduction
Adjusting the project by moving MySender forward caused startup failure with the following error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myConfig': Unsatisfied dependency expressed through field 'myListener'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myListener': Unsatisfied dependency expressed through field 'myService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myServiceImpl': Unsatisfied dependency expressed through field 'myManager'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myManager': Unsatisfied dependency expressed through field 'mySender'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mySender': Requested bean is currently in creation: Is there an unresolvable circular reference?Problem Analysis
BeanDefinition Scanning
XML‑based Bean definitions are now rare; the focus is on annotation‑based Bean definitions. Scanning order follows alphabetical order of folders and files.
ComponentScan processing occurs before @Bean . During scanning, BeanDefinitions are added to DefaultListableBeanFactory according to the scanning order.
BeanDefinition Overriding
MyConfigdefines MySender with @Bean , while MySender class is also annotated with @Component . In SpringBoot 2.0.3, the @Configuration + @Bean definition overrides the @Component definition, making the component annotation ineffective for MySender.
Bean Instantiation Order
BeanDefinitions drive instance creation; MySender 's @Component determines its instantiation order, which is earlier than MyConfig, MyListener, MyServiceImpl, and MyManager.
Theoretically, beans scanned earlier are instantiated earlier, but property injection can cause later‑scanned beans to be instantiated prematurely.
Root Cause of the Error
Because MySender is scanned first and its BeanDefinition from MyConfig overrides the component definition, Spring uses the constructor with a MyListener parameter to create MySender. This triggers a chain of dependencies that eventually leads to the “unresolvable circular reference” error, effectively a variant of constructor‑based circular dependency.
Potential Fixes
Since Spring cannot handle constructor‑based circular dependencies, avoid them by removing MyConfig and adjusting MySender to use setter injection, @PostConstruct, or other patterns that break the constructor cycle.
6 Garbage Collection Algorithms
ZGC uses a mark‑compact algorithm that moves all live objects to one side of the heap and then reclaims the remaining space.
6.1 Before JDK 16
ZGC reserved a portion of heap memory that could not be used for Java thread allocations. This simplified parallel collection but caused memory waste and potential OOM during object relocation.
6.2 JDK 16 Improvements
JDK 16 introduced in‑place object relocation for ZGC, eliminating the need for reserved memory. ZGC now dynamically chooses between reserved‑heap and in‑place relocation based on available regions.
Summary
BeanDefinition scanning follows alphabetical order of packages and files.
BeanDefinition overriding does not affect the scanning order; the bean name position in the definition list remains unchanged.
Instantiation order generally follows scanning order, but property injection can cause earlier instantiation of dependent beans.
Spring version matters; implementation details may differ across versions.
ZGC’s mark‑compact algorithm reduces STW pauses to a few milliseconds, with only three STW phases.
Because ZGC lacks generational collection, it can produce “floating garbage” that is reclaimed in subsequent cycles.
Source: 转自:青石路 Link: https://www.cnblogs.com/youzhibing/p/15835048.html
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
