Circular dependency: The only guide you will ever need

Posted By :Harshit Verma |31st October 2018

Each service in the service layer is probably having other services, which will be injected using @Autowire. When the services count starts growing, a circular dependency occurs. It does not have to indicate the design problem. It's enough that the central service, which is autowired in many services, consuming one of the other services, the circular dependency will likely arise.

The circular dependency will cause Spring Application Context to fail and the symptom is an error which is a circular dependency. It occurs when a bean A1 depends on another bean B1, and bean B1 depends on the bean A1 as well.

 

For dealing with the circular dependency in the spring we are having the following possible solutions.

1> Redesign

2> Use @Lazy

3> Use Setter/Field Injection

4> Use @PostConstruct

5> Implement ApplicationContextAware and InitializingBean

1> Redesign :-

        When we have a circular dependency, it’s you have a design problem and the responsibilities are not well separated. we should have to redesign the components properly so that the hierarchy is well designed and no chance for circular dependencies.

 

2> Use @Lazy :-

        The simplest path to break the cycle is saying Spring to initialize one of the beans lazily. Instead of fully initializing the bean, it will create a proxy to inject it into another bean. The injected bean will only be fully created when it is first needed. 

@Component

public class A {

 

    private B b;

 

    @Autowired

    public A(@Lazy B b) {

        this.b = b;

    }

}

 

3> Use Setter/Field Injection :-

                One of the most popular workarounds, also what Spring documentation proposes, is using setter injection.

Simply put if change the ways your beans are wired to use the setter injection (or field injection) instead of the constructor injection – that does address the problem. This way Spring creates beans, but the dependencies are not injected until they are needed.

 

 

@Component

public class A {

 

    private B b;

 

    @Autowired

    public void setB( b) {

        this.b = b;

    }

 

    public B getB() {

        return b;

    }

}

 

@Component

public class B {

 

    private A a;

 

    private String message = "Hello guys";

 

    @Autowired

    public void setA(A a) {

        this.a = a;

    }

 public String getMessage() {

        return message;

    }

}

 

4> Use @PostConstruct :-

            Another way to break the cycle is injecting a dependency using the @Autowired on one of the beans, and then use the method annotated with the @PostConstruct to set another dependency.

@Component

public class A {

 

    @Autowired

    private B b;

 

    @PostConstruct

    public void init() {

        b.a(this);

    }

 

    public B b() {

        return b;

    }

}

 

@Component

public class B {

 

    private A a;

     

    private String message = "Hello guys";

 

    public void setA(A a) {

        this.a = a;

    }

     

    public String getMessage() {

        return message;

    }

}

 

5> Implement ApplicationContextAware and InitializingBean :-

                              If one of the beans implements ApplicationContextAware, the bean has access to Spring context and can extract another bean from there. Implementing InitializingBean we indicate that the bean has to do some actions after all its properties have been set in the case, we want to manually set the dependency.

@Component

public class A implements ApplicationContextAware, InitializingBean {

 

    private B b;

 

    private ApplicationContext context;

 

    public B getB() {

        return b;

    }

 

    @Override

    public void afterPropertiesSet() throws Exception {

        circB = context.getBean(B.class);

    }

 

    @Override

    public void setApplicationContext(final ApplicationContext ctx) throws BeansException {

        context = ctx;

    }

}

 

 

 

@Component

public class B {

 

    private A a;

 

    private String message = "Hello guys";

 

    @Autowired

    public void setA(A a) {

        this.a = a;

    }

 

    public String getMessage() {

        return message;

    }

}

 

 


About Author

Harshit Verma

Harshit is a bright Web Developer with expertise in Java and Spring framework and ORM tools Hibernate.

Request For Proposal

[contact-form-7 404 "Not Found"]

Ready to innovate ? Let's get in touch

Chat With Us