Okt 15 2009

Solve the circular reference problem with Guice and Spring

Published by at 8:46 PM under Guice,Spring

  


The problem

Just imagine you run into a case where two objects are dependent on each other. The following picture and code snippet shows one such relationship.

Circular reference problem

Circular reference problem



Server.java

public class Server {
  private final Client client;

  public Server(Client client) {
  	this.client = client;
  }
}



Client.java

public class Client {
  private final Server server;

  public Client(Server server) {
  	this.server = server;
  }
}


Both Server and Client refer to the same instances of each other, using Constructor-Injection. Server refers to Client, which refers back to Server in a circle.


The solution for Spring

As you can see, you can’t directly use constructor wiring to make circular referents point to one another. To break the circularity without affecting the overall semantic of interdependence, is to introduce a proxy. First you have to decouple the Server and Client with interfaces.


Server.java

public interface Server{
}



Client.java

public interface Client {
}



ServerImpl.java

public class ServerImpl implements Server {
  private final Client client;

  public ServerImpl(Client client) {
  	this.client = client;
  }
}



ClientImpl.java

public class ClientImpl implements Client {
  private final Server server;

  public ClientImpl(Server server) {
  	this.server = server;
  }
}


The dependencies of ServerImpl and ClientImpl are now on a contract (interface) of each other, rather than a concrete class. This is where the proxy comes in:

ServerProxy.java

public class ServerProxy implements Server {
  private Server delegate;

  public void setDelegate(Server delegate) {
    this.delegate = delegate;
}


The ServerProxy is wired with setter injection, allowing ServerImpl and ClientImpl to declare their fields immutable and use constructor injection.
solution

This is the corresponding Spring-Configuration:

applicationContext.xml

<beans>
		<bean id="serverProxy" class="ServerProxy">
				<property name="delegate" ref="host" />
	  </bean>

	  <bean id="server" class="ServerImpl">
				<constructor-arg ref="client"/>
	  </bean>

	  <bean id="client" class="ClientImpl">
				<constructor-arg ref="serverProxy"/>
	  </bean>
</beans>




The solution for Guice

Solving the circular reference problem with Guice is similar to Spring. All you need is to configure your bindings.

MyModule.java

public class MyModule extends AbstractModule {

  @Override
  public void configure() {
    bind(Server.class).to(ServerImpl.class).in(Singleton.class);
    bind(Client.class).to(ClientImpl.class).in(Singleton.class);
  }
}


The Guice injector automatically provides the proxy so that the correct order of the construction would be guaranteed.

That’s it smile

Technorati Tags: , , ,

2 responses so far

2 Responses to “Solve the circular reference problem with Guice and Spring”

  1. William Shulman sagt:

    Hi-

    There is another solution for Spring that does not require a proxy at all. Make the client and server object properties of each other rather that implementing this is a way that requires each as a constructor argument to the other (i.e. make no-arg constructors for ClientImpl and ServerImpl and have a ‘client’ property in Server and a ‘server’ property in Client. Then Spring will do the magic (of course you will need to make appropriate changes in the xml wiring so properties vs constructors are used).

    -will

  2. Berghie Monami sagt:

    Mr. Siegfried Bolz , this article is very helpful , thank you for your sharing .
    i’ve implemented this and it solved my problem . But when i added 1 more proxy (3 class -dependency) , it went error . i think this solution only for 2 class -dependency .
    CMIW ,

    Regards,
    Berghie