我的代码库中有以下场景:
//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() {
//...
}
}
在下面的课程中我们进行注射:
@Named
@Stateless
public class BusinessManager {
@PersistenceContext(unitName = "default")
private EntityManager em;
@Inject
private HelperUtil helperUtil ;
//...
}
Q1:何时调用默认构造函数实际初始化的HelperUtil实例?当注入它的第一个客户端(如BusinessManager)在应用服务器(在我的情况下是JBoss)启动时被实例化(并且那个容器将被容器初始化,因为它被注释为@Stateless)?
Q2:在上面的展示中,HelperUtil是否仍然是单例,只要容器以外没有客户端通过直接调用构造函数而不是通过DI获取实例来请求实例?
问题3:在这种情况下使用DI和@Inject比直接调用构造函数(HelperUtil helper = new HelperUtil();)有什么好处?
解决方法:
这取决于,但你可以控制这些事件来执行一些代码,例如:
如果您需要在应用程序启动时执行bean,则需要将@Startup注释添加到bean中.
如果需要初始化bean而无需访问其他注入资源,则可以使用普通构造函数.
如果在初始化bean时需要执行某些方法,则在方法中使用@PostConstruct注释.
您需要记住,创建取决于bean的范围,在您的情况下,这是一个无状态bean,如果某个客户端注入它并且没有其他可用实例,则将创建bean,如果是singleton则将创建bean只需一次,一般来说,bean将在需要时创建(单例bean初始化直到第一个客户端使用它,或者在启动时使用注释)
编辑:
对于第三个问题,优点是如果您在HelperUtil中使用资源或其他bean,它们将使用适当的值进行初始化,例如,如果您使用实体管理器或帮助程序中的其他bean.如果您的帮助程序只处理静态方法或其他简单实用程序之类的东西,那么您就是正确的,优点是没有,您可以简单地像静态帮助程序类一样进行管理,但如果您需要EE资源,则需要按顺序管理bean获取所有注入和资源
编辑2:
经过多年的编程和在Java和C#Core中使用依赖注入,我可以补充一点:问题3非常开放,使用DI将允许您的代码:
>减少耦合,如果你改变你的构造函数,那么你将不得不去搜索所有新的ObjectModified(oldParams)来添加新的参数
>更容易测试,因为你可以将“假对象”作为依赖项注入,避免加载所有系统并为测试准备状态,例如,如果你想检查一些取决于当前小时的代码,你可以在测试模式下连接一个虚假的提供者,总是提供相同的小时或一些序列
>避免周期性依赖,其中A类依赖于B而B取决于A,通常这更复杂,如
ClasssA -> ClasssB -> ClasssC -> ClasssA
当存在这种依赖关系时,你可以开始一个修改,然后修改使用它的类,依此类推……直到你发现自己修改了同一个类,所以你开始在一个循环中,因为它之间的通信路径你的对象很复杂.
当您使用DI时,可以在早期检测到此循环,因此您可以重新考虑您的体系结构以避免这种生产力黑洞
DI是一个非常强大的工具,可以保持大项目的可维护性,现在存在于很多环境和框架中,因为它非常有用,如果这仍然不能说服你,你可以尝试在Spring boot,PlayFramework,Net Core中启动一个项目, Java EE,Ruby on Rails ……以及其他许多将其作为正常流程并构建中等大小的应用程序,然后在没有DI的情况下尝试