Inyección asistida por Guice en las profundidades de la jerarquía de dependencia

Quiero llevar a cabo una cadena de elementos de procesamiento y conectarlos a través de Guice. Supongamos la siguiente ruta:

  • interface A implementada por la class AImpl necesita alguna entrada
  • interface B implementada por la class BImpl necesita A
  • interface C implementada por la class CImpl necesita B
  • interface D implementada por class DImpl necesita C

La dependencia de A solo puede resolverse en tiempo de ejecución y no en el momento de la configuración. El enfoque habitual sería utilizar la inyección asistida en este caso para crear una fábrica, que tome las instancias que faltan como parámetros, como esta:

 public interface AFactory { public A createA(String input); } 

Pero lo que realmente quiero es algo como esto:

 public interface DFactory { public D createD(String inputForA); } 

No quiero pasar manualmente dependencias específicas de AImpl través de toda la jerarquía. ¿Es posible lograr esto con Guice? Si no es así, ¿cuál es la mejor manera de eludir este problema de manera elegante y al mismo tiempo conservar los beneficios de la inyección?

Modo trampa: pega la input en una variable estática o singleton ThreadLocal . Configúrelo antes de que comience la tubería y límpielo una vez que termine. Enlaza todo lo demás a través de DI.

Fancy way: en A , consulte la @PipelineInput String inputString pero no la vincule en su inyector principal. De lo contrario, vincula las dependencias como lo harías normalmente, incluso refiriéndote a @PipelineInput en otras clases relacionadas con la @PipelineInput . Cuando necesites una D , DFactory de la implementación de una DFactory , a la que llamo PipelineRunner .

 public class PipelineRunner { @Inject Injector injector; // rarely a good idea, but necessary here public D createD(final String inputForA) { Module module = new AbstractModule() { @Override public void configure() { bindConstant(inputForA).annotatedWith(PipelineInput.class); } }; return injector.createChildInjector(new PipelineModule(), module) .getInstance(D.class); } } 

Naturalmente, los bashs de enlace para A , B , C y D fallarán fuera de PipelineRunner por falta de una @PipelineInput String @PipelineInput: obtendrá una CreationException cuando cree el inyector con esas dependencias insatisfechas, como descubrió, pero aquellas Las dependencias basadas en tuberías deberían ser fáciles de separar en un Módulo que instale en el inyector hijo.

Si esto le parece demasiado raro, recuerde que los PrivateModules también se ” implementan utilizando inyectores originales “, y que el objective de la dependency injections es hacer que una dependencia como inputForA esté disponible para todo el gráfico de objetos de forma desacoplada.

Veo tres opciones. Dependen de la frecuencia con que cambie la input de A

1) Vincula la input como una constante en tu módulo. Esto solo funciona, si conoce ese valor antes de crear el Injector y nunca desea cambiar el valor. Ver bindConstant

2) Use un submódulo privado que enlace A o el valor de input dentro de ese módulo. Básicamente puede tener dos o tres gráficos de instancia con diferente valor. Ver newPrivateBinder .

3) Use un Scope RequestScope , SessionScope , … De esta manera puede cambiar la entrada a menudo, pero debe ingresar / abandonar el scope en algún momento para definirlo. Consulte ámbitos personalizados para ver un ejemplo.

    Intereting Posts