我目前正在编写一些框架代码,为我们平台内的服务提供蓝图,以便服务实现者可以专注于服务特定逻辑而不是样板集成代码。依赖注入是通过 guice 完成的。
蓝图有 2 种类型的逻辑组件;
- 1 个也是唯一一个将服务与外界集成的集成组件(消息中间件等)
- 1-n 个业务逻辑组件
每个逻辑组件都依赖于集成组件。
集成组件依赖于所有逻辑组件。
由于这是框架代码,框架不知道任何具体细节,因此不可能静态声明依赖关系并形成依赖关系图。我想避免让服务实现者这样做,因为这意味着他们在重复自己(只是声明他们有 n 个业务逻辑模块意味着他们有这种循环依赖)。
我的问题是,在不让服务实现者编写样板代码的情况下,我可以采取哪些方法来完成这项工作?
请注意,此处不提供多重绑定,因为出于此问题范围之外的各种原因,每个业务逻辑组件都必须是 PrivateModule。
一个人为的例子来说明哪里
- 业务逻辑 = ModuleA、ModuleB、ModuleC
- 集成提供的依赖 = Wrapper
- 集成对业务逻辑的依赖是通过每个逻辑模块向 Wrapper 添加一些东西来建模的
这个例子可以通过改变来工作
@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;
}
}
}