我在一个项目中使用 Netty (4.0.4.Final),并且我一直遇到我需要排除的循环依赖。这个问题主要涉及分解循环依赖的概念,但我会为熟悉的人使用一些 Netty 术语。不过,由于我的问题实际上与 Netty 无关,所以我决定不标记它。
下面,我发布了我的代码,省略了我认为不相关的部分。
情况
我有一个MyServer
将 a 添加ChannelInboundHandlerAdapter
到 a的类Bootstrap
:
public class MyServer extends AbstractMyServer {
private Integer someInteger; //Using Integer just for example's sake.
public MyServer(MyServerInitializer initializer) {
//...
bootstrap.handler(initializer);
//...
}
public void updateInteger(Integer value) {
someInteger = value;
//Send an update packet to another server.
}
}
MyServerInitializer
需要添加ChannelInboundHandlerAdapter
一个ChannelPipeline
:
public class MyServerInitializer extends ChannelInitializer<SocketChannel> {
private ChannelInboundHandlerAdapter handler;
public MyServerInitializer(ChannelInboundHandlerAdapter handler) {
this.handler = handler;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new ObjectEncoder(),
new ObjectDecoder(),
handler);
}
}
在我正在谈论的情况下,我还有一个MyServerHandler
which 是构造函数参数:MyServerInitializer
public class MyServerHandler extends ChannelInboundHandlerAdapter {
private MyServer server;
public MyServerHandler(MyServer server) {
this.server = server;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Integer obj = (Integer) msg; //Remember just using Integer for example. Think of it as an Object rather than an Integer.
server.updateInteger(obj);
}
}
因此,循环依赖在初始化期间变得明显:
public static void main(String[] args) {
//I can't set a reference to MyServer instance here because it hasn't been created yet. I want to avoid the circular dependency here.
MyServerHandler handler = new MyServerHandler(...);
MyServerInitializer initializer = new MyServerInitializer(handler);
MyServer server = new MyServer(initializer);
}
可能的解决方案
重构为main()
我可以拉出 ofInteger someInteger
的MyServer
创建,在main()
函数范围内创建它,然后将它的引用注入到MyServerHandler
andMyServer
中。这当然MyServerHandler
可以直接修改它,而不必通过MyServer
. 缺点是它已在main()
现在的范围内声明。我不想对每个可能本质上需要由类修改的类成员执行此操作Handler
。
创建一个MyServerFactory
我读到的其中一个概念是将构造与使用分开。这很有意义,所以我试了一下下面的工厂模式实现。
public class MyServerFactory implements AbstractFactory<MyServer> {
public MyServer create() {
Integer someInteger = createInteger();
MyServerHandler handler = createHandler(someInteger);
MyServerInitializer initializer = createInitializer(handler);
return new MyServer(initializer);
}
/* creator methods for the different components above. */
}
但是,这似乎我只是将代码从main()
这个Factory
类中移了出来。
问题
- 如果我想注入不同的东西会发生什么
Handler
-MyServerInitializer
也许这个新Handler
的不接受 anInteger
作为论点。我必须Factory
为这种情况创建一个新的吗? - 拥有一个
Factory
可能只会创建单个实例的MyServer
? - 是否有其他选项可用于排除此循环参考?
粗体字是我在 StackOverflow 上提出这个问题的主要焦点。我觉得我必须在这里忽略一些更简单或更优雅的东西。我希望你们中一些更有经验的用户可以提供一些见解。请让我知道是否需要更多信息。
参考资料
- 使用依赖注入解决循环依赖
- Misko Hevery 的构造函数中的循环依赖和依赖注入
- Clean Code - Robert C. Martin 的敏捷软件工艺手册
- 设计模式:Erich Gamma 等人的可重用面向对象软件的元素。人