【发布时间】:2013-01-10 20:48:02
【问题描述】:
我目前正在编写一些框架代码,为我们平台内的服务提供蓝图,以便服务实现者可以专注于服务特定逻辑,而不是样板集成代码。依赖注入是通过 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;
}
}
}
【问题讨论】:
-
替换 'go()' 方法对我有用。你看到什么问题? Guice 是否抛出异常?
-
你指的是哪个 go() 方法?
-
你说“这个例子可以通过改变来工作..”我用第二个替换了第一个 go 方法: go(Container in) -> go(@Named("a") Container in, @Named("b") 容器 in2, @Named("c") 容器 in3)
-
啊好的,是的,这是一个可行的解决方案,但是它不符合“不要重复自己”的要求,这就是我所说的“我的问题是我可以采取什么方法来做到这一点在不让服务实现者编写样板代码的情况下工作?”。如果我使用这种方法,那么我会强制框架用户编写(不是很多)这样的代码来制作依赖图形式。我想避免这种解决方案。
-
所有业务逻辑组件是否都将实现相同的类型?
标签: java guice circular-dependency