Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring. Resolve circular dependency with java config and without @Autowired

I've got circular dependency and java config. While resolving it with xml config is very easy I can't resolve it with java config without @Autowired. Beans:

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}

public class B {
    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

I've tried this(I've read that with @Bean annotation Spring won't invoke method every time bean is referenced, but in this case it's actually been invoked all the time):

@Configuration
public class Config {
    @Bean
    public A a() {
        A a = new A();
        a.setB(b());
        return a;
    }

    @Bean
    public B b() {
        B b = new B();
        b.setA(a());
        return b;
    }
}

And this, with @Autowired of Configuration class fields:

@Configuration
public class Config {
    @Autowired
    A a;
    @Autowired
    B b;

    @Bean
    public A a() {
        A a = new A();
        a.setB(b);
        return a;
    }

    @Bean
    public B b() {
        B b = new B();
        b.setA(a);
        return b;
    }
}

Also I've tried all above with @Lazy annotation. Doesn't help. But works perfectly if I annotate setters of A and B with @Autowired. But it's not what I want right now. What am I doing wrong and is there any way to resolve Circular dependency in java config without usage of @Autowired?

like image 336
Artem Malinko Avatar asked Dec 23 '14 14:12

Artem Malinko


People also ask

How do you solve cyclic dependency in Spring?

A simple way to break the cycle is by telling Spring to initialize one of the beans lazily. So, instead of fully initializing the bean, it will create a proxy to inject it into the other bean. The injected bean will only be fully created when it's first needed.

How do you resolve circular dependency when it occurs?

To resolve the circular dependency, you must break the loop by replacing the dynamic reference to the bucket resource.

Where can we face the problem of circular dependency and which approach can resolve it?

Circular dependency problem can be overcome by using interfaces or events. So for the above problem, we can introduce an interface in between the “ MiddleTier ” and “ Dal ”. This interface project you will implement in the middle layer project on the “ Customer ” class.

How do you avoid circular dependencies?

To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.


2 Answers

The behavior you want to get is the following

A a = new A();
B b = new B();
a.setB(b);
b.setA(a);

@Bean methods don't give you that. They run to completion to provide a bean instance.

You basically have to partially create one of the instances, then finish initializing it when you've created the other.

@Configuration
class Config {
    @Bean
    public A a() {
        A a = new A();
        return a;
    }

    @Bean
    public B b() {
        B b = new B();
        A a = a();
        b.setA(a);
        a.setB(b);
        return b;
    }
}

or

@Bean
public B b(A a) {
    B b = new B();
    b.setA(a);
    a.setB(b);
    return b;
}
like image 152
Sotirios Delimanolis Avatar answered Oct 23 '22 06:10

Sotirios Delimanolis


Another approach using @Autowired and @Component is to use this pattern:

@Component
class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(final B b) {
        this.b = b;
    }
}


@Component
class B {
    private final A a;

    @Autowired
    public B(final A a) {
        this.a = a;
        a.setB(this);
    }

    public A getA() {
        return a;
    }
}

This eliminates the need for a separate @Configuration-class. Furthermore, the setB-method can possibly be package-protected if the classes exist in the same package to minimize scoping as much as possible.

like image 21
wassgren Avatar answered Oct 23 '22 08:10

wassgren