我知道有很多文章解释了如何在Java EE中使用CDI,但我很难弄清楚这实际带来了什么好处。例如,假设我有一个当前使用Foo实例的类。我可能会做
Foo myFoo = new Foo();
或
// Better, FooFactory might return a mock object for testing
Foo myFoo = FooFactory.getFoo();
我一直在阅读CDI,我可以这样做:
@Inject
Foo myFoo;
但为什么这比以前的工厂方法更好?我假设还有一些其他用例我不知道,但我还没有能够识别出来。
如果我已经理解了下面的回答,那么概念就是DI框架充当集中配置的主对象工厂。这是一个合理的解释吗?
更新
自从开始学习Spring以来,我现在更有意义了。以下段落取自 Spring in Practice ,以AccountService
类为例,后者使用AccountDao
的实例。我为长篇报道道歉,但我认为它真正触及了为什么注入资源提供超标准初始化的核心。
您可以使用new关键字构建AccountService,但服务层对象的创建很少如此简单。它们通常依赖于DAO,邮件发件人,SOAP代理等等。您可以在AccountService构造函数中(或通过静态初始化)以编程方式实例化每个依赖项,但这会导致硬件依赖性和级联更改,因为它们已被换出。
此外,您可以在外部创建依赖项,并通过setter方法或构造函数参数在AccountService上设置它们。这样做可以消除硬内部依赖关系(只要它们通过接口在AccountService中声明),但是你到处都有重复的初始化代码。以下是创建DAO并连接它的方法 由Spring方式决定你的AccountService:
<bean id="accountDao" class="com.springinpractice.ch01.dao.jdbc.JdbcAccountDao"/>
<bean id="accountService"
class="com.springinpractice.ch01.service.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
如上所述配置bean后,您的程序现在可以从Spring ApplicationContext请求AccountService
的实例,Spring DI框架将实例化需要实例化的所有内容。
答案 0 :(得分:46)
写CDI的人给了你一个大对象工厂;他们为你做了比你更好的工作。它是XML配置或注释驱动的,因此您不必将所有内容嵌入代码中。
与Spring一样,依赖注入引擎比你的工厂做得更多。它将需要不止一个工厂类和一行代码来复制它们提供的所有内容。
当然你不必使用它。你总是可以自由发明自己的轮子。你应该 - if your purpose is to learn how to make wheels或消除依赖关系。
但是,如果您只想开发应用程序,最好使用其他人提供的工具。
依赖注入的seminal article由Martin Fowler编写。我建议阅读它;八年后,它仍然很棒。
“仍然不清楚是什么”
以下是一些优点:
答案 1 :(得分:17)
使用依赖注入的目的是使用注入的东西的代码不依赖于工厂。使用您的工厂代码示例,您的代码中嵌入了静态方法调用,而DI方法则不需要这样。
注入myFoo
的东西不应该知道工厂。
答案 2 :(得分:5)
这是一个关于企业编程的重要而微妙的问题。
这个名字选择得很好:上下文和依赖项。
CDI与更好或更清晰的代码无关,而是确保大型组织可以构建复杂的分布式软件系统并共享数据。这是关于100%确保政府或其他官僚机构可以不加选择地为他们控制的每一个软件分发自包含,记录良好的软件包。请记住,现在几乎可以注入任何POJO。假设您正在构建某种类型的客户端应用程序,并且您希望它在角落中打印用户的第一个名称。
这家大公司的企业架构师希望你这样做 有这种能力,但作为初级软件工程师,没有 你把钥匙交给数据库的机会。
他们还希望通过网络保护数据,但是 公司没有支付任何工程师重新设计身份验证 客户每次需要共享一小段数据时。
他们希望您能够查询和更新 这个信息,但希望交易处理更高 水平比任何一个应用程序。
他们希望您能够在设置块中使用琐碎的模拟测试您的课程。
他们希望类之间的耦合涉及最少的静态方法。
一直等待......
大多数JSR可能都有“EAs希望能够......”埋藏在某个地方。
CDI是首选,因为它允许大(任意?)水平和垂直比例的应用程序共享上下文,依赖项,从而共享数据。
用福勒的话来说:
“问题是我如何建立这个链接,以便我的lister类 对实现类一无所知,但仍然可以与之交谈 实例来做它的工作。“
“但如果我们希望以不同的方式部署这个系统,我们需要 使用插件来处理与这些服务的交互,以便我们可以 在不同的部署中使用不同的实现。“
“这些容器使用的方法是确保任何用户 插件遵循一些允许单独汇编程序的约定 模块将实现注入lister。“
简而言之,它们允许对复杂的企业应用程序进行集中的“命令和控制”。 Java EE 是一个系统化,可靠的抽象过程,而CDI是它的化身,它运作良好,几乎使它看不见。它使复杂应用程序的拼接几乎是微不足道的。
还有两件事:
请注意,CDI与“服务定位器模式”(Java EE中称为JNDI)并行存在,如果客户端开发人员需要在许多相同类型的替代方案中进行选择,则CDI更为可取。
在许多情况下,CDI比所需的火力更强,特别是非企业(字面意思)的情况。
答案 3 :(得分:4)
在高级别,与CompSci上的大多数内容一样,它提供 一个间接级别 (或抽象),否则将在您的应用程序中以{{ 1}}。这种间接性带来了松散耦合的代码,这使得事物变得模块化,这使得以更简单的方式更换,服务,测试等类或子系统变得容易。
请注意,间接/抽象有许多设计和模式 - 依赖注入只是一个。
您问题的另一方面是“为何选择CDI?” - 好吧,因为有人已经为你完成了这项工作。您可以始终构建自己的东西,但目标是建立一个必须在预算内按时执行的真实世界系统通常是浪费时间。当有米其林星级厨师愿意为你做这项工作时,为什么还要买杂货和做饭?