Spring circular reference example
This is an old thread, so I guess you almost forgot about the issue, but I want to let you know about the mystery. I encountered the same problem, and mine didn't go away magically, so I had to resolve the problem. I'll solve your questions step by step.
1. Why you couldn't reproduce the circular reference exception?
Because Spring takes care of it. It creates beans and injects them as required.
2. Then why does your project produce the exception?
- As @sperumal said, Spring may produce circular exception if you use constructor injection
- According to the log, you use Spring Security in your project
- In the Spring Security config, they do use constructor injection
- Your beans which injects the
authenticationManager
had the circular reference
3. Then why has the exception gone away mystically?
The exception may or may not occur depends on the creation order of beans. I guess you made several *context.xml
files or so, and load them with config something like below in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*-context.xml</param-value>
</context-param>
The xml files will be loaded by XmlWebApplicationContext
class and the loading order of files are not guaranteed. It just loads files from the file system. The problem is here. There's no problem if the class loads the application context file first, because your beans are already created when they are used for the construction injection of Spring Security. But, if it loads the Spring Security context file first, the circular reference problem occurs, because Spring tries to use your beans in the constructor injection before they had been created.
4. How to solve the problem?
Force the loading order of the xml files. In my case, I loaded the security context xml file at the end of the application context file by using <import resource="">
. The loading order can be changed depends on environments even with the same code, so I recommend setting the order to remove potential problems.
You could use @Lazy
to indicate that the bean is lazily created, breaking the eager cycle of autowiring.
The idea is that some bean on the cycle could be instantiated as a proxy, and just at the moment it is really needed it will be initialized. This means, all beans are initialized except the one that is a proxy. Using it for the first time will trigger the configuration and as the other beans are already configured it will not be a problem.
From one Issue in Spring-Jira:
@Lazy annotation that can be used in conjunction with @Configuration to indicate that all beans within that configuration class should be lazily initialized. Of course, @Lazy may also be used in conjunction with individual @Bean methods to indicate lazy initialization on a one-by-one basis. https://jira.springsource.org/browse/SJC-263
Meaning that annotating your bean as @Lazy
would be enough. Or if you prefer just annotate the configuration class as @Lazy
as follows:
@Configuration
@Lazy
public class Config {
@Bean
public ClassA classA() {
return new ClassA();
}
@Bean
public ClassB classB() {
return new ClassB();
}
}
If you implement an interface of your beans this will work quite well.
According to Spring documentation, it is possible to get Circular dependency issue or BeanCurrentlyInCreationException
by using constructor injection.
The solution to fix the issue is to use setters instead of Constructor injection.
Reference http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.