2013-01-10 20 views
1

我目前正在編寫一些框架代碼,爲我們的平臺中的服務提供藍圖,以便服務實現者可以專注於特定於服務的邏輯而不是樣板集成代碼。依賴注入是通過guice完成的。如何處理跨多個guice私有模塊的循環依賴關係?

藍圖有2種邏輯組件;

  1. 1和整合與外界服務只有1集成組件(消息傳送中間件等)
  2. 1-正業務邏輯組件

每個邏輯組件依賴的集成組件上。

集成組件取決於所有的邏輯組件。

由於這是框架代碼,框架沒有意識到任何具體細節,因此不可能靜態聲明依賴關係並形成依賴關係圖。我想避免讓服務實現者這樣做,因爲這意味着他們正在重複自己(只是聲明他們有n個業務邏輯模塊意味着他們有這種循環依賴)。

我的問題是我可以採取什麼方法使這項工作沒有使服務實施者寫出樣板代碼?

請注意,多重綁定在此處不可用,因爲在此問題範圍之外的各種原因,每個業務邏輯組件都必須是PrivateModule。

一個人爲的例子來說明,其中

  1. 業務邏輯=由積分提供ModuleA,ModuleB,ModuleC
  2. 依賴性=包裝
  3. Integration的業務邏輯依賴關係是由每個邏輯模塊添加建模東西包裝

這個例子可以通過更改

@Provides @Exposed @Named("result") 
public String go(Container in) { 
    return in.format(); 
} 

@Provides @Exposed @Named("result") 
public String go(@Named("a") Container in, @Named("b") Container in2, @Named("c") Container in3) { 
    return in.format(); 
} 

即,通過實際創建一個循環依賴關係。

import com.google.inject.Exposed; 
import com.google.inject.Guice; 
import com.google.inject.Injector; 
import com.google.inject.Key; 
import com.google.inject.PrivateModule; 
import com.google.inject.Provides; 
import com.google.inject.Singleton; 
import com.google.inject.name.Named; 
import com.google.inject.name.Names; 

import java.util.ArrayList; 
import java.util.List; 

public class GuiceCircularDependencyTest { 

    public static void main(String[] args) { 
     Injector in = Guice.createInjector(new Owner()); 
     String result = in.getInstance(Key.get(String.class, Names.named("result"))); 
     System.out.println("Result is: " + result); 
    } 

    public static class Owner extends PrivateModule { 
     @Override 
     protected void configure() { 
      bind(Container.class).in(Singleton.class); 
      install(new Integration()); 
      install(new ModuleA()); 
      install(new ModuleB()); 
      install(new ModuleC()); 
      expose(String.class).annotatedWith(Names.named("result")); 
     } 
    } 

    public static class ModuleA extends PrivateModule { 

     @Override 
     protected void configure() { 

     } 

     @Provides @Exposed @Named("a") 
     public Container go(Container in, Wrapper prefix) { 
      in.add(prefix + "A"); 
      return in; 
     } 
    } 

    public static class ModuleB extends PrivateModule { 

     @Override 
     protected void configure() { 

     } 

     @Provides @Exposed @Named("b") 
     public Container go(Container in, Wrapper prefix) { 
      in.add(prefix + "B"); 
      return in; 
     } 
    } 

    public static class ModuleC extends PrivateModule { 

     @Override 
     protected void configure() { 

     } 

     @Provides @Exposed @Named("c") 
     public Container go(Container in, Wrapper prefix) { 
      in.add(prefix + "C"); 
      return in; 
     } 
    } 

    public static class Integration extends PrivateModule { 
     @Override 
     protected void configure() { 
      bind(Wrapper.class).toInstance(new Wrapper("Module")); 
      expose(Wrapper.class); 
     } 

     @Provides @Exposed @Named("result") 
     public String go(Container in) { 
      return in.format(); 
     } 
    } 

    public static class Container { 
     private List<String> strings = new ArrayList<>(); 

     public void add(String string) { 
      strings.add(string); 
     } 

     public String format() { 
      return strings.toString(); 
     } 
    } 

    public static class Wrapper { 
     private final String prefix; 

     public Wrapper(String prefix) { 
      this.prefix = prefix; 
     } 

     @Override 
     public String toString() { 
      return prefix; 
     } 
    } 
} 
+0

更換'go()'方法適用於我。你看到什麼問題? Guice是否拋出異常? –

+0

哪個go()方法你的意思是? – Matt

+0

你說過:「這個例子可以通過改變來工作。「我將第一個go方法替換爲第二個方法:go(Container in) - > go(@Named(」a「)Container in,@Named(」b「)Container in2,@Named(」c「)Container in3) –

回答

0

一種解決方法,其允許Multibinder跨私人模塊共享,被包裹PrivateModuleAbstractModule實現,它簡單地安裝PrivateModule並結合暴露關鍵Multibinder

import com.google.inject.AbstractModule; 
import com.google.inject.Exposed; 
import com.google.inject.Guice; 
import com.google.inject.Injector; 
import com.google.inject.Key; 
import com.google.inject.PrivateModule; 
import com.google.inject.Provides; 
import com.google.inject.multibindings.Multibinder; 
import com.google.inject.name.Named; 
import com.google.inject.name.Names; 

import java.util.Set; 

public class GuiceCircularDependencyTest { 

    public static void main(String[] args) { 
     Injector in = Guice.createInjector(new Owner()); 
     String result = in.getInstance(Key.get(String.class, Names.named("result"))); 
     System.out.println("Result is: " + result); 
    } 

    public static class Owner extends PrivateModule { 
     @Override 
     protected void configure() { 
      Multibinder<String> multi = Multibinder.newSetBinder(binder(), String.class); 
      install(new Integration()); 
      install(new ModuleWrapper<>(new ModuleA(), multi)); 
      install(new ModuleWrapper<>(new ModuleB(), multi)); 
      install(new ModuleWrapper<>(new ModuleC(), multi)); 
      expose(String.class).annotatedWith(Names.named("result")); 
     } 
    } 

    public static class ModuleWrapper<T> extends AbstractModule { 
     private final WrappablePrivateModule<T> inner; 
     private final Multibinder<T> multi; 

     public ModuleWrapper(WrappablePrivateModule<T> inner, 
          Multibinder<T> multi) { 
      this.inner = inner; 
      this.multi = multi; 
     } 

     @Override 
     protected void configure() { 
      install(inner); 
      multi.addBinding().to(inner.getExposedKey()); 
     } 
    } 

    public static abstract class WrappablePrivateModule<T> extends PrivateModule { 

     @Override 
     protected void configure() { 

     } 

     public abstract Key<T> getExposedKey(); 
    } 

    public static class ModuleA extends WrappablePrivateModule<String> { 

     private static final String SUFFIX = "A"; 

     @Override 
     public Key<String> getExposedKey() { 
      return Key.get(String.class, Names.named(SUFFIX)); 
     } 

     @Provides @Exposed @Named(SUFFIX) 
     public String expose(Wrapper prefix) { 
      return prefix + SUFFIX; 
     } 
    } 

    public static class ModuleB extends WrappablePrivateModule<String> { 

     private static final String SUFFIX = "B"; 

     @Override 
     public Key<String> getExposedKey() { 
      return Key.get(String.class, Names.named(SUFFIX)); 
     } 

     @Provides @Exposed @Named(SUFFIX) 
     public String expose(Wrapper prefix) { 
      return prefix + SUFFIX; 
     } 
    } 

    public static class ModuleC extends WrappablePrivateModule<String> { 

     private static final String SUFFIX = "C"; 

     @Override 
     public Key<String> getExposedKey() { 
      return Key.get(String.class, Names.named(SUFFIX)); 
     } 

     @Provides @Exposed @Named(SUFFIX) 
     public String expose(Wrapper prefix) { 
      return prefix + SUFFIX; 
     } 
    } 

    public static class Integration extends PrivateModule { 
     @Override 
     protected void configure() { 
      bind(Wrapper.class).toInstance(new Wrapper("Module")); 
      expose(Wrapper.class); 
     } 

     @Provides @Exposed @Named("result") 
     public String go(Set<String> in) { 
      return in.toString(); 
     } 
    } 

    public static class Wrapper { 
     private final String prefix; 

     public Wrapper(String prefix) { 
      this.prefix = prefix; 
     } 

     @Override 
     public String toString() { 
      return prefix; 
     } 
    } 
} 
+0

是的,這就是我的想法。 –