Dependência ciclica entre dois @Component

13 respostas
R

Existe alguma restrição ou problema de ter uma restrição ciclica entre dois componentes do VRaptor?

Ex:

@Component
public class A
{
public A(B b)
{
...
}
}

@Component
public class B
{
public B(A a)
{
...
}
}

13 Respostas

Lucas_Cavalcanti

tem… qdo vc usa injeção por construtor não dá pra eu criar a instancia de A sem criar a de B e vice versa… um deles precisa fazer injeção por setter, ou método. Para isso use o @Inject (Guice e Spring) ou o @Autowired (Spring)

R

Estou usando o Spring juntamente com o VRaptor. Preciso mapear o componente em algum lugar para usá-lo no @Inject, ou o VRaptor já se encarrega disso para mim?

Tentei usar o @Inject dessa maneira:

@Component  
public class A  
{  
public A(B b)  
{  
...  
}  
}  
  
@Component  
public class B  
{  

@Inject
A a;

}

E o seguinte erro é disparado:

Requested bean is currently in creation: Is there an unresolvable circular reference?
Lucas_Cavalcanti

tenta deixar os dois com o @Inject.

R

Funcionou!

Aproveitando o tópico: Uma vez li que o VRaptor só permitia injeções pelo construtor para respeitar o padrão good-citizen do objeto. No entanto, essa injeção utilizando @Inject seria uma injeção pelo setter.

Existe alguma diferença entre injetar no construtor ou via setter?

Lucas_Cavalcanti

se vc sempre usar esse objeto injetado pelo spring, não… mas se vc precisar testar o objeto, é melhor que a injeção seja pelo construtor.

R

Se eu tenho a injeção no construtor no teste preciso ter um mock e passá-lo no construtor, certo? Não teria o mesmo resultado de passar o mock pelo setter da variável?

Lucas_Cavalcanti

sim, o mesmo resultado.

a diferença é que o construtor obriga a passar as dependências, e o setter não.

R

Estava fazendo mais alguns testes…

Se eu deixo o @Inject só de um lado, ele dá certo ao injetar de um lado, mas da erro para injetar do outro lado.
Se eu deixo o @Inject dos dois lados, dá erro nos dois lados.

Vou isolar o problema e fazer mais alguns testes… enquanto isso tem outra sugestão?

R

Montei o contexto abaixo e realizei o teste.

@Resource
public class TesteController 
{

	public TesteController(A a)
	{
		this.a = a;
	}
	
	private final A a;
	
	@Get(value="/testar")
	public void teste()
	{
		System.out.println("Teste...");
	}
	
}

@Component
public class A 
{

	@Inject
	private B b;
	
}

@Component
public class B 
{

	@Inject
	private A a;
	
}

Ao acessar o @Resource ocorreu o seguinte erro:

Error creating bean with name 'b': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.cauirs.sgv.controladores.A br.com.cauirs.sgv.controladores.B.a; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?

Procurei no GUJ outras pessoas que passaram pelo mesmo problema usando VRaptor, e não achei. Refatorar a classe seria a única solução?

R

O @Inject é do pacote javax.Inject?

Lucas_Cavalcanti

como vc tá usando o spring, tenta trocar o @INject pelo @Autowired, e colocar a anotação no setter, e não no atributo.

R

Lucas, fiz o teste aqui, mas acontece o mesmo erro.

@Component
public class A 
{

	private B b;

	@Autowired
	public void setB(B b)
	{
		this.b = b;
	}
	
	public B getB()
	{
		return this.b;
	}
	
}

@Component
public class B 
{
	
	private A a;
	
	@Autowired
	public void setA(A a)
	{
		this.a = a;
	}
	
	public A getA()
	{
		return a;
	}
	
}

@Resource
public class TesteController 
{
	
	private A a;
	
	@Autowired
	public void setA(A a)
	{
		this.a = a;
	}
	
	public A getA()
	{
		return a;
	}
	
	@Get(value="/testar")
	public void teste()
	{
		System.out.println("Teste...");
	}
	
}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void br.com.cauirs.sgv.controladores.TesteController.setA(br.com.cauirs.sgv.controladores.A); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void br.com.cauirs.sgv.controladores.A.setB(br.com.cauirs.sgv.controladores.B); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void br.com.cauirs.sgv.controladores.B.setA(br.com.cauirs.sgv.controladores.A); nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Lucas_Cavalcanti

http://blog.richardadamdean.com/?p=49

básicamente faça uma dessas coisas:

  • refatore o seu código pra não precisar desse ciclo
  • receba o ApplicationContext como dependência e faça o lookup em uma das classes
  • ou use um post processor
Criado 9 de março de 2012
Ultima resposta 12 de mar. de 2012
Respostas 13
Participantes 2