我的代码库中有以下情形:

//this bean, which will be injected,
//is not annotated
public class HelperUtil {
   //only default constructor with no args

   public void doThis(String _in) {
      //...
   }

   public void doThat() {
      //...
   }
}

在下面的类中,我们进行注入(inject):
@Named
@Stateless
public class BusinessManager {

    @PersistenceContext(unitName = "default")
    private EntityManager em;

    @Inject
    private HelperUtil helperUtil ;

    //...
}

问题1:什么时候将通过调用默认构造函数实际初始化将要注入(inject)的HelperUtil实例?当启动应用服务器(在我的情况下为BusinessManager)时实例化了将其注入(inject)的第一个客户端(例如JBoss)时,该操作完成了吗(该容器将被初始化,因为它被标注为@Stateless)?

问题2:在上述展览中,只要容器之外的其他客户端都没有直接通过调用构造函数而不是通过HelperUtil获取实例来请求实例,那么singleton仍将是DI吗?

问题3:与直接调用构造函数(@Inject)相比,在这种情况下使用DI和HelperUtil helper = new HelperUtil();有什么优势?

最佳答案

这取决于,但是您可以控制这些事件以执行一些代码,例如:
如果您需要在应用启动时执行bean,则需要向bean添加@Startup批注。
如果您需要在不访问其他注入(inject)资源的情况下初始化bean,则可以使用常规构造函数。
如果在初始化Bean时需要执行某些方法,请在该方法中使用@PostConstruct批注。

您需要记住,创建取决于bean的范围,在这种情况下,它是无状态bean,如果某些客户端注入(inject)了bean,并且没有其他可用实例,则将创建bean,如果为singleton,那么将创建bean。仅一次,通常将在需要它们时创建该bean(一个单例bean初始化,直到第一个客户端使用它,或者在使用注释启动时)

编辑:
对于第三个问题,好处是,如果您在HelperUtil中使用资源或其他bean,它们将使用适当的值进行初始化,例如,如果您使用实体管理器或帮助程序中的其他bean。如果您的助手只处理静态方法或其他简单实用程序之类的东西,那么您是对的,好处是没有,您可以像静态助手类一样简单地进行管理,但是如果您需要EE资源,则需要按顺序管理bean获取所有注入(inject)和资源

编辑2:
经过几年的编程并在Java和C#Core中使用依赖注入(inject),我可以添加:问题3非常开放,使用DI将使您的代码能够:

  • 耦合较少,如果更改构造函数,则必须搜索所有new ObjectModified(oldParams)以添加新参数
  • 更易于测试,因为您可以将“假对象”作为依赖项注入(inject),从而避免了加载所有系统并为测试准备状态的需求,例如,如果您要检查一些取决于当前时间的代码,您可以在测试模式下连接伪造的提供程序以提供始终相同的小时数,或提供一些顺序
  • 避免周期性依赖,即类A依赖于B而B依赖于A,通常这会更复杂,例如



  • 当存在这种依赖关系时,您可以开始修改,然后修改使用它的类,依此类推……直到您发现自己像以前一样修改了相同的类!,因此您开始一个循环,因为两者之间的通信路径您的对象很复杂。
    当您使用DI时,可以早日检测到这种周期,因此您可以重新考虑您的体系结构,以避免这种生产力的黑洞

    DI是使大型项目保持可维护性的非常强大的工具,现在已经存在于许多环境和框架中,因为它非常有用,如果仍然不能说服您,则可以尝试在Spring boot,PlayFramework,Net Core, Java EE,Ruby on Rails ....和许多其他已将其包含在内的标准流程,并构建了中等大小的应用程序,然后尝试不使用DI

    10-01 17:57
    查看更多