Spring circular reference example

50,250

Solution 1

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.

Solution 2

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.

Solution 3

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.

Share:
50,250
robbin
Author by

robbin

Updated on January 25, 2021

Comments

  • robbin
    robbin over 3 years

    I have a circular reference in one of my projects at work using spring, which I am unable to fix, and fails with the following error at startup:

    'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
    

    I tried to recreate the same problem at a smaller level in a sample project (without all the details of my work project). I have however been unable to come up with a plausible scenario where spring fails with an error. Here's what I have:

    public class ClassA {
        @Autowired
        ClassB classB;
    }
    
    public class ClassB {
        @Autowired
        ClassC classC;
    }
    
    @Component
    public class ClassC {
        @Autowired
        ClassA classA;
    }
    
    @Configuration
    public class Config {
        @Bean
        public ClassA classA() {
            return new ClassA();
        }
    
        @Bean
        public ClassB classB() {
            return new ClassB();
        }
    }
    

    I have a similar scenario in my project, which fails, and I was expecting spring to complain in my sample project as well. But it works fine! Can someone give me a simple example of how to break spring with the circular reference error?

    Edit: I fixed the issue using javax.inject.Provider. The only other difference in the 2 projects was the annotations used were javax.inject.Inject and javax.annotation.ManagedBean in place of @Autowired and @Component.