Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring circular reference example

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.

like image 829
robbin Avatar asked Jul 05 '12 16:07

robbin


People also ask

What is circular reference Spring?

What Is a Circular Dependency? A circular dependency occurs when a bean A depends on another bean B, and the bean B depends on bean A as well: Bean A → Bean B → Bean A. Of course, we could have more beans implied: Bean A → Bean B → Bean C → Bean D → Bean E → Bean A.

What is a circular dependency in Java?

A circular or cyclic dependency is a situation where two or more independent modules or components rely on each other to function properly. This is referred to as mutual recursion. Circular dependency generally occurs in a modular framework while defining a dependency between modules or components.


3 Answers

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.

like image 117
Francisco Spaeth Avatar answered Sep 25 '22 08:09

Francisco Spaeth


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.

like image 22
Sanghyun Lee Avatar answered Sep 24 '22 08:09

Sanghyun Lee


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.

like image 10
sperumal Avatar answered Sep 26 '22 08:09

sperumal