在 IoC 容器中将依赖项设置为 NULL 并在运行时提供依赖项是一个不好的做法吗?

2023-12-09

我有一个SocketManager包含一个类Socket和其他领域。除Socket可以在使用 DI 框架构建对象图期间注入。我的想法是简单地通过留下来预先构建整个对象图Socket清空并在运行时设置它。这将使我能够完成SocketManager在代码中的某一点实例化并在整个程序中使用该实例(因为它已经通过 DI 框架设置为依赖项)?这是“注入”运行时依赖项的标准方法还是不好的做法?
抽象工厂似乎是一个坏主意,原因有两个:a)它每次都会创建一个不同的对象b)它在我想要创建对象的每个地方都需要运行时参数

让我说明一下我的问题:

套接字管理器类:

public class SocketManager {
    //i'll only receive the socket at runtime
    Socket socket; 
    //this object is available at compile-time and can be injected through the DI container
    InjectableObject obj;
}

在我的代码 [CodePosition1] 的某个地方,我将收到如下所示的套接字:

public class SocketCreator{
    SocketManager socketManager; //will be injected through DI container at startup
    Socket socket = this.serverSocket.accept();
    // at this point the socket manager is fully initialized
    socketManager.setSocket(socket); 
}

在许多其他地方 [CodePosition2] 我现在可以使用 SocketManager 依赖项

public class RandomClass {
    //injected at compile-time through DI container, but only usable after [CodePosition1]
    // was executed
    SocketManager socketManager; 
    ...
        socketManager.getSocket().doSth()
    ...
}

问题是SocketManager直到运行时 [CodePosition1] 才完全初始化,所以除了在 SocketManager 上使用 init() 或 setter 来“完成”SocketManager 的初始化之外,我不知道有任何其他方法。然而,这是一个有漏洞的抽象,正如这篇文章中所解释的:是否存在初始化通过 DI 容器创建的对象的模式


最好从一开始就构建完整的对象图。注射null应该避免使用值,因为它使消费类变得复杂。

然而,就你而言,这似乎是Socket不是一个“真正的”组件,而是运行时数据。如上所述here,您应该防止在构造期间将运行时数据注入到对象图中。

该文章提供了两种解决方案来解决该问题,但还有更多解决方案。然而,抽象工厂通常是not正如您已经提到的,一个好的解决方案,并且这篇博文从更一般的意义上描述了抽象工厂的问题是什么。段落6.2 of 这本书甚至从 DI 的角度更详细地讨论了抽象工厂的问题。

博客文章中给出的解决方案是使用“上下文”抽象。例如,在您的情况下,SocketContext接口,允许您获取Socket一旦消费者的方法被调用,消费者的运行时值,因此after消费者的对象图被构建。例如:

public interface SocketContext
{
    Socket get_CurrentSocket();
}

另一种选择是使用代理类,它可以隐藏真实的代理类Socket或真实的SocketManager(取决于您可以放置​​代理的级别)。这使得消费者不知道某些运行时数据需要在幕后初始化,并且在第一次调用时可能会延迟完成。例如:

public class SocketManagerLazyProxy : SocketManager
{
    private SocketManager mananger;

    public void DoSomething()
    {
        if (manager == null) manager = new RealSocketManager(new Socket());
        manager.DoSomething();
    }   
}

另一个选项是设置Socket构建对象图后使用属性注入来获取值。这允许您更早地构建对象图,并在请求到来时设置运行时值,方法是在请求到来时设置它:

void HandleRequest(RequestData data)
{
    SocketManager manager = GetSocketManagerForThisRequest();
    manager.Socket = new Socket();
    Handler handler = GetHandler(data.Name);
    handler.Handle(data);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 IoC 容器中将依赖项设置为 NULL 并在运行时提供依赖项是一个不好的做法吗? 的相关文章

  • 如何在 Eclipse 中用阿拉伯语读写

    我在 eclipse 中编写了这段代码来获取一些阿拉伯语单词 然后打印它们 public class getString public static void main String args throws Exception PrintS
  • 使用 Checkstyle Plugin 时从插件调用代码时出现问题:“org.eclipse.jface”

    我正在尝试在 Rational Software Architect 7 0 0 4 上使用 eclipse cs 插件 我最近卸载了旧的 beta2 版本并安装了 beta3 插件本身按照之前的配置工作 但是每当我尝试通过 Windows
  • 使用 Spring 时实例化对象,用于测试与生产

    使用 Spring 时 应该使用 Spring 配置 xml 来实例化生产对象 并在测试时直接实例化对象 这样的理解是否正确 Eg MyMain java package org world hello import org springf
  • Java 泛型/类型调度问题

    考虑以下程序 import java util List import java util ArrayList public class TypeTest public static class TypeTestA extends Type
  • MI设备中即使应用程序被杀死,如何运行后台服务

    您好 我正在使用 alaram 管理器运行后台服务 它工作正常 但对于某些 mi 设备 后台服务无法工作 我使用了服务 但它无法工作 如何在 mi 中运行我的后台服务 MI UI有自己的安全选项 所以你需要的不仅仅是上面提到的粘性服务 你需
  • 方法断点可能会大大减慢调试速度

    每当向方法声明行添加断点 在 Intellij IDEA 或 Android Studio 中 时 都会出现一个弹出窗口 方法断点可能会大大减慢调试速度 为什么会这样戏剧性地减慢调试速度 是我的问题吗 将断点放在函数的第一行有什么不同 Th
  • Android - 除了普通 SSL 证书之外还验证自签名证书

    我有一个通过 SSL 调用 Web 服务的 Android 应用程序 在生产中 我们将拥有由受信任的 CA 签名的普通 SSL 证书 但是 我们需要能够支持自签名证书 由我们自己的 CA 签名 我已经成功实施了接受自签名证书的建议解决方案
  • JavaFX - setVisible 隐藏元素但不重新排列相邻节点

    在 JavaFX 中 如果我有一个场景有 2VBox元素和每个VBox有多个Label in it 如果我设置顶部VBox to 无形的 为什么底部VBox 不向上移动顶部的场景VBox was The VBox is 无形的但我希望其他物
  • 所有junit测试后的清理

    在我的项目中 我必须在所有测试之前进行一些存储库设置 这是使用一些棘手的静态规则来完成的 然而 在所有测试之后我不知道如何进行清理 我不想保留一些神奇的静态数字来引用所有测试方法的数量 我应该一直维护它 最受赞赏的方法是添加一些侦听器 该侦
  • cucumber-junit-platform-engine 中的功能文件发现

    In cucumber junit我使用的库 CucumberOptions定义功能文件位置 package com mycompany cucumber import cucumber api CucumberOptions import
  • 使用 java 按电子邮件发送日历邀请

    我正在尝试使用 java 发送每封电子邮件的日历邀请 收件人收到电子邮件 但不会显示接受或拒绝的邀请 而是将该事件自动添加到他的日历中 我正在使用 ical4j jar 构建活动 邀请 private Calendar getInvite
  • 想要开发像 Facebook 这样的网站 - 处理数百万个请求 - 高性能 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想用 Java 开发一个像 Fac
  • 使用 Guava 联合两个 ImmutableEnumSets

    我想联合两个ImmutableEnumSets来自番石榴 这是我的尝试 public final class OurColors public enum Colors RED GREEN BLUE YELLOW PINK BLACK pub
  • 空对象模式以避免空检查?

    最近 我遇到了空对象设计模式 我的同事说它可以用来消除整个代码中遇到的空指针检查 例如 假设 DAO 类返回有关 Customer 的信息 在名为 CustomerVO 的值对象中 我的主类应该提取名字和电子邮件 ID 并向客户发送电子邮件
  • 具有多种值类型的 Java 枚举

    基本上我所做的是为国家编写一个枚举 我希望不仅能够像国家一样访问它们 而且还能够访问它们的缩写以及它们是否是原始殖民地 public enum States MASSACHUSETTS Massachusetts MA true MICHI
  • 让JScrollPane控制多个组件

    对于我的应用程序 我正在设计一个脚本编辑器 目前我有一个JPanel其中包含另一个JPanel保存行号 位于左侧 以及JTextArea用于允许用户输入代码 位于右侧 目前 我已经实施了JScrollPane on the JTextAre
  • 在 Selenium WebDriver 上如何从 Span 标签获取文本

    在 Selenium Webdriver 上 如何从 span 标记检索文本并打印 我需要提取文本UPS Overnight Free HTML代码如下 div id customSelect 3 class select wrapper
  • Spock模拟inputStream导致无限循环

    我有一个代码 gridFSFile inputStream bytes 当我尝试这样测试时 given def inputStream Mock InputStream def gridFSDBFile Mock GridFSDBFile
  • 重写Object类的finalize()方法有什么用?

    据我所知 在java中如果我们想手动调用垃圾收集器 我们可以执行System gc 1 我们在重写的finalize 方法中做了哪些操作 2 如果我们想手动调用JVM垃圾收集器 是否需要重写finalize 方法 我们在重写的 Finali
  • Spring Boot MSSQL Kerberos 身份验证

    目前在我的春季靴子中application properties文件中 我指定以下行来连接到 MSSql 服务器 spring datasource url jdbc sqlserver localhost databaseName spr

随机推荐