Friday, November 9, 2012

Breaking a circular dependency in Spring

Have you ever seen a stack trace like this and wondered what to do:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanA' defined in file [\BeanA.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [BeanB]: : Error creating bean with name 'beanB' defined in file [\BeanB.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [BeanA]: : Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanB' defined in file [\BeanB.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [BeanA]: : Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?
 at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
...
 at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
 at (Main.java:12)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanB' defined in file [\BeanB.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [BeanA]: : Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?
 at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
...
org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
 ... 15 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:297)
...
Then you probably have code like this:
@Component
public class BeanA {

 private final BeanB beanB;

 @Autowired
 public BeanA(BeanB beanB) {
  this.beanB = beanB;
 }

 @Override
 public String toString() {
  return beanB.getClass().getSimpleName() + " from " + this.getClass().getSimpleName();
 }

}

@Component
public class BeanB {

 private final BeanA beanA;

 @Autowired
 public BeanB(BeanA beanA) {
  this.beanA = beanA;
 }

 @Override
 public String toString() {
  return beanA.getClass().getSimpleName() + " from " + this.getClass().getSimpleName();

 }

}
How do you break such a circular reference in Spring? You could and should consider whether your code could be structured better. However, if you have considered this, then read on to find a way to break the circular reference. Take look at the Provider interface. Then take a look at this code:
@Component
public class BeanA {

 private final Provider<BeanB> beanB;

 @Autowired
 public BeanA(Provider<BeanB> beanB) {
  this.beanB = beanB;
 }

 @Override
 public String toString() {
  return beanB.get().getClass().getSimpleName() + " from " + this.getClass().getSimpleName();
 }

}

@Component
public class BeanB {

 private final Provider<BeanA> beanA;

 @Autowired
 public BeanB(Provider<BeanA> beanA) {
  this.beanA = beanA;
 }

 @Override
 public String toString() {
  return beanA.get().getClass().getSimpleName() + " from " + this.getClass().getSimpleName();

 }

}
If you run this code:
public class Main {

 public static void main(String... args) throws InterruptedException, ExecutionException {

  ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[] { "META-INF/spring/app-context.xml" });
  BeanA beanA = applicationContext.getBean(BeanA.class);
  BeanB beanB = applicationContext.getBean(BeanB.class);
  System.err.println(beanA);
  System.err.println(beanB);

 }

}
You will see this instead of the above stack trace:
BeanB from BeanA
BeanA from BeanB
Note: the above is just a toy example to illustrate the point. In the code without use of the Provider interface you could actually just delete the constructors and put @Autowired on the Bean* fields (removing the final modifier) and it would work.