If constructor injection is used, a circular dependency scenario that cannot be parsed may be created.
What is circular dependency
Circular dependence is actually circular reference, that is, two or more beans hold each other and eventually form a closed loop. For example, A depends on B, B depends on C, and C depends on A. As shown in the figure below:
Note that this is not a loop call to the function, but an interdependence of the object. Loop calls are actually a dead loop unless there is an end condition.
The circular dependency scenarios in Spring include:
(1) Circular dependence of the constructor (2) Circular dependence of the field attribute.
How to detect if there is a circular dependency
It is relatively easy to detect circular dependencies. When the bean is created, it can mark the bean. If the recursive call is back and finds that it is being created, it means that the circular dependency is.
Here is the situation I encountered, the code structure is as follows:
SpringSecurity configuration class:
@Configurationpublic class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsService userDetailsService; /** * Inject UserDetailsService through the configuration class constructor */ @Autowired public BrowserSecurityConfig(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } /** * Declare the encryption encoder in the configuration class */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } ... ...}UserDetailsService class:
@Componentpublic class MyUserDetailService implements UserDetailsService { private final PasswordEncoder passwordEncoder; private Logger logger = LoggerFactory.getLogger(getClass()); /** * Inject PasswordEncoder through the constructor */ @Autowired public MyUserDetailService(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } ... ...}After running, Spring throws the following error message:
Description:
The dependencies of some of the beans in the application context form a cycle:
┌────┐
| browserSecurityConfig defined in file [D:/CODE/Java/IdeaProjects/mango-security/mango-security-browser/target/classes/stu/mango/security/browser/BrowserSecurityConfig.class]
↑ ↓
| myUserDetailService defined in file [D:/CODE/Java/IdeaProjects/mango-security/mango-security-browser/target/classes/stu/mango/security/browser/MyUserDetailService.class]
└────┘
In this example, BrowserSecurityConfig injects the UserDetailsService instance through the constructor, and the UserDetailsService is injected into the PasswordEncoder declared in the BrowserSecurityConfig through the constructor.
In summary, the circular dependence of Spring Bean means that class A needs to inject an instance of class B (or a bean declared in B) into the constructor, while class B needs to inject an instance of class A (or a bean declared in A) into the constructor. If the beans of class A and class B are configured to inject each other, the Spring IoC container detects this loop reference at runtime and raises a BeanCurrentlyInCreationException. Unlike the typical case (without circular dependencies), the circular dependency between bean A and bean B forces one of the beans to be injected into the other before being fully initialized (this is a typical "chicken first or egg first" scenario).
Solution
To put it simply, it is not to use constructor-based dependency injection. It can be solved by the following method.
Use the @Autowired annotation on the field and let Spring decide to inject at the right time. 【recommend】
Replace constructor-based dependency injection with setter-based dependency injection to solve circular dependency.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.