Spring. Resolve circular dependency with java config and without #Autowired - java

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?

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;
}

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.

I want to add another possible solution for your code. Instead of setting circular dependencies right in the config:
#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;
}
}
You could also let the spring do the work with the power of #Autowired annotation.
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
return a;
}
#Bean
public B b() {
B b = new B();
return b;
}
}
public class A {
private B b;
#Autowired
public setB(B b) { this.b = b; }
}
public class B {
private A a;
#Autowired
public setA(A a) { this.a = a; }
}
Of course it is non trivial from the "clean/readable/understandable" point of view because now your configuration is mixed in #Configuration and class itself. But as circular dependencies are quite rare, we could afford the hack.

Related

Hierarchical Bean Dependency in Spring Boot

I have a hierarchy of beans dependency of same parent class S as:
A -> B -> C
where Bean A contains bean B, bean B contains C with code structure something like this:
public class A extends S {
private S successor;
}
public class B extends S {
private S successor;
}
public class C extends S {
private S successor;
}
And when implementing I have
A a = new A();
B b = new B();
C c = new C();
a.successor = b;
b.successor = c;
What I really want to do here to set all the immediate above bean creation and dependency relationships in the Configuration instead of hardcoding in the code; something like:
#Configuration
public class MyConfig {
#Bean
public A a {
return new A();
}
#Bean
public B b {
B b = new B();
A a; // somehow get the bean A here
a.successor = b;
}
#Bean
public C c {
C c = new C();
B b; // somehow get the bean b here
b.successor = c;
}
}
Any inputs on how to go about this using Spring boot Dependency injection?
You can pass required beans as arguments to your provider methods.
#Bean
public A a() {
return new A();
}
#Bean
public B b(A a) {
B b = new B();
a.successor = b;
return b;
}
#Bean
public C c(B b) {
C c = new C();
b.successor = c;
return c;
}
However, this sets the a.successor only when B is injected somewhere. I believe this is not what you expect, and inverting the construction chain is desired:
#Bean
public A a(B b) {
A a = new A();
a.successor = b;
return a;
}
#Bean
public B b(C c) {
B b = new B();
b.successor = c;
return b;
}
#Bean
public C c() {
return new C();
}

Inconsistent circular dependency with constructor+setter injection

I have following beans in my application
#Component
public class Main {
private A a;
#Inject
public Main(A a) {
this.a = a;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
#Component
public class A {
private B b;
#Inject
public void setB(B b) {
this.b = b;
}
public B getB() {
return b;
}
}
#Component
public class B {
private A a;
#Inject
public void setA(A a) {
this.a = a;
}
public A getA() {
return a;
}
}
Component scan is for the package where this three classes were placed.
The above beans works in some environment and fails in other environment with circular dependency while create bean Main
Why is this circular dependency not very consistent?
The problem is that your bean A depends on bean B, and bean B depends on bean A. First of all, I would suggest rethinking your design. However, there are workarounds like using #Postconstruct, or #Lazy.
Here's a good reference, which explains what happens and different ways to solve the problem: http://www.baeldung.com/circular-dependencies-in-spring

Easymock call autowired object method

Let's say I have Following classes:
public class A {
#Autowired B b;
public void doSomething(){
b.doSomeThingElse();
}
#Component
#Autowired C c;
public class B {
public void doSomethingElse(){
c.doIt();
}
How can I test A when you know I want to mock c.doIt() but want to call b.doSomethingElse(); with EasyMock?
Thanks in advance
#Autowired is nice but tend to make us forget about how to test. Just add a setter for b and c.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B();
b.setC(c);
A a = new A();
a.setB(b);
a.doSomething();
verify(c);
Or use constructor injection.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B(c);
A a = new A(b);
a.doSomething();
verify(c);
In this case, your classes become:
public class A {
private B b;
public A(B b) { // Spring will autowired by magic when calling the constructor
this.b = b;
}
public void doSomething() {
b.doSomeThingElse();
}
}
#Component
public class B {
private C c;
public B(C c) {
this.c = c;
}
public void doSomethingElse(){
c.doIt();
}
}

Constructor based dependency injection inject property based objects

I have two classes
Class B {
#Resource
C c;
}
Class A {
private final B b;
public A(B b) {
this.b = b;
}
}
Then class A is initialized using Spring through #Bean annotation as follows:
#Configuration
public class AppConfigHelper {
#Bean
public C getC() {
return new C();
}
#Bean
public B getB() {
return new B();
}
#Bean
public A getA() {
return new A(getB());
}
}
The problem that I end up with is C getting null in object of type B. Is there a solution to this problem?
I have to get A initialized this way only as the B is the old code which I do not want to touch at this point of time.

Spring autowire is giving nullPointerException

This is the controller which calls thread 'TestRunner'.
#Controller
#RequestMapping("/welcome")
public class HomeController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView addCustomerPage() throws Exception{
ModelAndView modelAndView = new ModelAndView("customer/add-customer-form");
A a = new A();
B b = new B();
C c = new C();
TestRunner runner = new TestRunner(a, b, c);
Thread t = new Thread(runner);
t.start();
return modelAndView;
}
}
This is my thread which calls service HomeService. This service is autowired but still I getting null pointer exception when I call homeService.testMeth(a,b,c);
#Controller
public class TestRunner implements Runnable{
private A a;
private B b;
private C c;
#Autowired
private HomeService homeService;
public TestRunner() {
super();
// TODO Auto-generated constructor stub
}
public TestRunner(A a, B b, C c){
this.a = a;
this.b = b;
this.c = c;
}
public void run() {
// TODO Auto-generated method stub
homeService.testMeth(a,b,c);
}
}
This is service class.
#Service
public class HomeService {
public void testMeth(A a, B b, C c){
System.out.println("inside....");
}
}
Is this because of I am creating 'TestRunner' object with 'new' ?
Is this because of I am creating 'TestRunner' object with 'new' ?
Yes, It is because of this you get NullpointerExceptoin.
To fix the issue change the following:
Mark the following three classes A, B, C as component - if not
already done. Ensure the package is in component scan path:
#Component
public class A {
#Component
public class B {
#Component
public class C {
Then Autowire the A, B, C instances in TestRunner. Also change the annotation of TestRunner to #Component
#Component
public class TestRunner implements Runnable{
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
In HomeRunner create an instance field for TestRunner and autowire it. Remove the instansiation code with new operator for TestRunner.

Categories

Resources