I know there are a lot of articles out there that explain how to use CDI in Java EE but I'm having trouble figuring out what advantage this actually brings. For example, suppose I have a class that currently uses an instance of Foo. I might either do
我知道有很多文章解释了如何在Java EE中使用CDI,但我无法弄清楚这实际带来了什么优势。例如,假设我有一个当前使用Foo实例的类。我也许会这样做
Foo myFoo = new Foo();
or
要么
// Better, FooFactory might return a mock object for testing
Foo myFoo = FooFactory.getFoo();
I keep reading that with CDI I can do:
我一直在阅读CDI,我能做到:
@Inject
Foo myFoo;
but why is this better than the previous factory based approach? I assume there is some other use case that I'm not aware of but I haven't been able to identify this.
但为什么这比以前的工厂方法更好?我假设还有一些其他用例,我不知道,但我无法识别这一点。
If I've understood the responses below, the concept is that the DI framework acts as a master object factory that is configured centrally. Is this a reasonable interpretation?
如果我理解了下面的响应,那么概念就是DI框架充当集中配置的主对象工厂。这是一个合理的解释吗?
Update
更新
I've since started learning Spring and this now makes a lot more sense. The paragraph below is taken from Spring in Practice taking an example of an AccountService
class which in turn, uses an instance of AccountDao
. I apologise for the long quote but I think it really gets to the heart of why injected resources offer something over standard initialisation.
我从那时起开始学习Spring,现在这更有意义了。下面的段落取自Spring in Practice,以一个AccountService类为例,后者又使用AccountDao的一个实例。我为长篇报道道歉,但我认为它真正解释了为什么注入资源提供了超过标准初始化的东西。
You could have constructed the AccountService using the new keyword, but the creation of service layer objects is rarely so straightforward. They often depend on DAOs, mail senders, SOAP proxies, and whatnot. You could instantiate each of those dependencies programmatically in the AccountService constructor (or through static initialization), but that leads to hard dependencies and cascading changes as they’re swapped out.
您可以使用new关键字构建AccountService,但服务层对象的创建很少如此简单。它们通常依赖于DAO,邮件发件人,SOAP代理等等。您可以在AccountService构造函数中(或通过静态初始化)以编程方式实例化每个依赖项,但这会导致硬件依赖性和级联更改,因为它们已被换出。
Additionally, you could create dependencies externally and set them on the AccountService via setter methods or constructor arguments. Doing so would eliminate the hard internal dependencies (as long as they were declared in the AccountService by interface), but you’d have duplicated initialization code everywhere. Here’s how you create a DAO and wire it up to your AccountService the Spring way:
此外,您可以在外部创建依赖项,并通过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>
Having configured the beans as above, your program can now request an instance of AccountService
from the Spring ApplicationContext and the Spring DI framework will look after instantiated everything that needs instantiating.
如上所述配置bean后,您的程序现在可以从Spring ApplicationContext请求AccountService实例,Spring DI框架将实例化需要实例化的所有内容。
4 个解决方案
#1
45
The people that wrote CDI gave you one big object factory; they did the work for you, better than you would. It's XML configuration or annotation driven, so you don't have to embed everything in code.
写CDI的人给了你一个大对象工厂;他们为你做的工作比你更好。它是XML配置或注释驱动的,因此您不必将所有内容嵌入代码中。
Dependency injection engines, like Spring, do a lot more than your factory. It'll take more than one factory class and one line of code to duplicate all that they offer.
像Spring这样的依赖注入引擎比你的工厂做得更多。它需要不止一个工厂类和一行代码来复制它们提供的所有内容。
Of course you don't have to use it. You are always free to invent your own wheel. And you should - if your purpose is to learn how to make wheels or eliminate dependencies.
当然你不必使用它。你总是可以*发明自己的*。你应该 - 如果你的目的是学习如何制造*或消除依赖性。
But if you want to just develop applications, it's better to use the tools that others provide when they give you an advantage.
但是,如果您只想开发应用程序,最好使用其他人提供的工具。
The seminal article on dependency injection was written by Martin Fowler. I'd recommend reading it; it's still great, eight years later.
关于依赖注入的开创性文章由Martin Fowler撰写。我建议阅读它;八年后,它仍然很棒。
"still not clear on what the more is"
“还不清楚是什么”
Here are a few advantages:
以下是一些优点:
- Looser coupling
- 松耦合
- Easier testing
- 更容易测试
- Better layering
- 更好的分层
- Interface-based design
- 基于接口的设计
- Dynamic proxies (segue to AOP).
- 动态代理(segue to AOP)。
#2
17
The purpose of using dependency injection is so that the code using the thing that's injected doesn't have a dependency on the factory. With your factory code example there's a static method call embedded in your code that is not needed there with the DI approach.
使用依赖注入的目的是使用注入的东西的代码不依赖于工厂。使用您的工厂代码示例,您的代码中嵌入了一个静态方法调用,而DI方法则不需要这样。
The thing that is being injected with myFoo
shouldn't have to know about the factory.
用myFoo注入的东西不应该知道工厂。
#3
4
At a high level, as with most things on CompSci, it offers a level of indirection (or abstraction) that would otherwise be hardcoded in your application as Foo myFoo = new Foo();
. That indirection brings about loosely coupled code, which makes things modular, which makes it easy to replace, service, test etc classes or sub-systems in a simpler manner.
在高级别,就像CompSci上的大多数事情一样,它提供了一定程度的间接(或抽象),否则将在您的应用程序中硬编码为Foo myFoo = new Foo();.这种间接性带来了松散耦合的代码,这使得事物变得模块化,这使得以更简单的方式更换,服务,测试等类或子系统变得容易。
Note that there are many designs and patterns for indirection/abstraction - dependency injection is just one.
请注意,间接/抽象有许多设计和模式 - 依赖注入只是一个。
The other aspect of your question is "Why CDI?" - well, because someone has already done the work for you. You can always build your own stuff, but it's usually a waste of time when the objective is to build a real world system that must perform under budget and on time. Why bother with groceries and cooking when there is a Michelin starred chef who's willing to do that work for you?
你问题的另一个方面是“为什么选择CDI?” - 好吧,因为有人已经为你完成了这项工作。你总是可以建立自己的东西,但目标是建立一个必须在预算和时间内完成的真实世界系统,这通常是浪费时间。当有米其林星级厨师愿意为您做这项工作时,为什么还要买杂货和做饭呢?
#4
4
This is an important and subtle question about what enterprise programming is all about.
这是一个关于企业编程的重要而微妙的问题。
The name is well chosen: contexts and dependencies.
这个名字选择得很好:上下文和依赖项。
CDI has nothing to do with better or cleaner code, it's about ensuring that large organizations can build complex, distributed software systems and share data. It's about making 100% sure that governments or other bureaucracies can indiscriminately distribute self-contained, well-documented packages for every piece of software they control. Remember that these days, virtually any POJO can be injected.
CDI与更好或更清晰的代码无关,而是确保大型组织可以构建复杂的分布式软件系统并共享数据。这是关于100%确保*或其他官僚机构可以不加选择地为他们控制的每一个软件分发自包含,记录良好的软件包。请记住,现在几乎可以注入任何POJO。
Let's say you're building a client app of some sort, and you want it to print the first name of the user in the corner.
假设您正在构建某种类型的客户端应用程序,并且您希望它在角落中打印用户的第一个名称。
-
The enterprise architects of this large company would like you to have this capability, but as a junior software engineer, there is no chance of you being handed the keys to the DB.
这家大公司的企业架构师希望您具备此功能,但作为初级软件工程师,您不可能将密钥交给数据库。
-
They would also like to secure the data across the network, but the company isn't paying any engineers to re-engineer an authentication client every time they need to share a scrap of data.
他们还希望通过网络保护数据,但每次需要共享一小段数据时,公司都不会向任何工程师支付重新设计身份验证客户端的费用。
-
They would like for you to be able to be able to query and update this info, but would like transactions to be handled at a higher level than any one app.
他们希望您能够查询和更新此信息,但希望事务处理的级别高于任何一个应用程序。
-
They would like for you to be able to test your classes with trivial mocks in setup blocks.
他们希望您能够在设置块中使用琐碎的模拟测试您的类。
-
They would like for coupling between classes to involve a minimum of static methods.
他们希望类之间的耦合涉及最少的静态方法。
-
And on and on and on...
并且一直在......
Most JSRs probably have a "EAs would like to be able to..." buried inside somewhere.
大多数JSR可能都有“EAs希望能够......”埋藏在某个地方。
CDI is preferred because it allows apps of large (arbitrary?) horizontal and vertical scales to share contexts, dependencies, and therefore data.
CDI是首选,因为它允许大(任意?)水平和垂直比例的应用程序共享上下文,依赖项,因此共享数据。
In Fowler's words:
用福勒的话来说:
"The problem is how can I make that link so that my lister class is ignorant of the implementation class, but can still talk to an instance to do its work."
“问题是如何建立这个链接,以便我的列表类不知道实现类,但仍然可以与实例通信来完成它的工作。”
" But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments."
“但是如果我们希望以不同的方式部署这个系统,我们需要使用插件来处理与这些服务的交互,这样我们就可以在不同的部署中使用不同的实现。”
"The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister."
“这些容器使用的方法是确保插件的任何用户遵循一些允许单独的汇编程序模块将实现注入列表器的约定。”
In a nutshell, they allow for centralized "command and control" of complex enterprise applications. Java EE is a systematized, reliable process for abstraction and CDI is a an incarnation of it that works so well, it almost makes it invisible. It makes the stitching together of complex apps almost trivial.
简而言之,它们允许对复杂的企业应用程序进行集中的“命令和控制”。 Java EE是一个系统化,可靠的抽象过程,CDI是它的化身,它运作良好,几乎使它看不见。它使复杂应用程序的拼接几乎是微不足道的。
Two more things:
还有两件事:
-
Note that CDI exists peacefully alongside the "service locator pattern", known as JNDI in Java EE, which is preferable if the client developer will need to choose among many identically-typed alternatives.
请注意,CDI与“服务定位器模式”(Java EE中称为JNDI)并行存在,如果客户端开发人员需要在许多相同类型的替代方案中进行选择,则更为可取。
-
CDI is more firepower than is needed in many cases, especially non-enterprise (literally) cases.
CDI比许多情况下需要的火力更强,特别是非企业(字面意思)的情况。
#1
45
The people that wrote CDI gave you one big object factory; they did the work for you, better than you would. It's XML configuration or annotation driven, so you don't have to embed everything in code.
写CDI的人给了你一个大对象工厂;他们为你做的工作比你更好。它是XML配置或注释驱动的,因此您不必将所有内容嵌入代码中。
Dependency injection engines, like Spring, do a lot more than your factory. It'll take more than one factory class and one line of code to duplicate all that they offer.
像Spring这样的依赖注入引擎比你的工厂做得更多。它需要不止一个工厂类和一行代码来复制它们提供的所有内容。
Of course you don't have to use it. You are always free to invent your own wheel. And you should - if your purpose is to learn how to make wheels or eliminate dependencies.
当然你不必使用它。你总是可以*发明自己的*。你应该 - 如果你的目的是学习如何制造*或消除依赖性。
But if you want to just develop applications, it's better to use the tools that others provide when they give you an advantage.
但是,如果您只想开发应用程序,最好使用其他人提供的工具。
The seminal article on dependency injection was written by Martin Fowler. I'd recommend reading it; it's still great, eight years later.
关于依赖注入的开创性文章由Martin Fowler撰写。我建议阅读它;八年后,它仍然很棒。
"still not clear on what the more is"
“还不清楚是什么”
Here are a few advantages:
以下是一些优点:
- Looser coupling
- 松耦合
- Easier testing
- 更容易测试
- Better layering
- 更好的分层
- Interface-based design
- 基于接口的设计
- Dynamic proxies (segue to AOP).
- 动态代理(segue to AOP)。
#2
17
The purpose of using dependency injection is so that the code using the thing that's injected doesn't have a dependency on the factory. With your factory code example there's a static method call embedded in your code that is not needed there with the DI approach.
使用依赖注入的目的是使用注入的东西的代码不依赖于工厂。使用您的工厂代码示例,您的代码中嵌入了一个静态方法调用,而DI方法则不需要这样。
The thing that is being injected with myFoo
shouldn't have to know about the factory.
用myFoo注入的东西不应该知道工厂。
#3
4
At a high level, as with most things on CompSci, it offers a level of indirection (or abstraction) that would otherwise be hardcoded in your application as Foo myFoo = new Foo();
. That indirection brings about loosely coupled code, which makes things modular, which makes it easy to replace, service, test etc classes or sub-systems in a simpler manner.
在高级别,就像CompSci上的大多数事情一样,它提供了一定程度的间接(或抽象),否则将在您的应用程序中硬编码为Foo myFoo = new Foo();.这种间接性带来了松散耦合的代码,这使得事物变得模块化,这使得以更简单的方式更换,服务,测试等类或子系统变得容易。
Note that there are many designs and patterns for indirection/abstraction - dependency injection is just one.
请注意,间接/抽象有许多设计和模式 - 依赖注入只是一个。
The other aspect of your question is "Why CDI?" - well, because someone has already done the work for you. You can always build your own stuff, but it's usually a waste of time when the objective is to build a real world system that must perform under budget and on time. Why bother with groceries and cooking when there is a Michelin starred chef who's willing to do that work for you?
你问题的另一个方面是“为什么选择CDI?” - 好吧,因为有人已经为你完成了这项工作。你总是可以建立自己的东西,但目标是建立一个必须在预算和时间内完成的真实世界系统,这通常是浪费时间。当有米其林星级厨师愿意为您做这项工作时,为什么还要买杂货和做饭呢?
#4
4
This is an important and subtle question about what enterprise programming is all about.
这是一个关于企业编程的重要而微妙的问题。
The name is well chosen: contexts and dependencies.
这个名字选择得很好:上下文和依赖项。
CDI has nothing to do with better or cleaner code, it's about ensuring that large organizations can build complex, distributed software systems and share data. It's about making 100% sure that governments or other bureaucracies can indiscriminately distribute self-contained, well-documented packages for every piece of software they control. Remember that these days, virtually any POJO can be injected.
CDI与更好或更清晰的代码无关,而是确保大型组织可以构建复杂的分布式软件系统并共享数据。这是关于100%确保*或其他官僚机构可以不加选择地为他们控制的每一个软件分发自包含,记录良好的软件包。请记住,现在几乎可以注入任何POJO。
Let's say you're building a client app of some sort, and you want it to print the first name of the user in the corner.
假设您正在构建某种类型的客户端应用程序,并且您希望它在角落中打印用户的第一个名称。
-
The enterprise architects of this large company would like you to have this capability, but as a junior software engineer, there is no chance of you being handed the keys to the DB.
这家大公司的企业架构师希望您具备此功能,但作为初级软件工程师,您不可能将密钥交给数据库。
-
They would also like to secure the data across the network, but the company isn't paying any engineers to re-engineer an authentication client every time they need to share a scrap of data.
他们还希望通过网络保护数据,但每次需要共享一小段数据时,公司都不会向任何工程师支付重新设计身份验证客户端的费用。
-
They would like for you to be able to be able to query and update this info, but would like transactions to be handled at a higher level than any one app.
他们希望您能够查询和更新此信息,但希望事务处理的级别高于任何一个应用程序。
-
They would like for you to be able to test your classes with trivial mocks in setup blocks.
他们希望您能够在设置块中使用琐碎的模拟测试您的类。
-
They would like for coupling between classes to involve a minimum of static methods.
他们希望类之间的耦合涉及最少的静态方法。
-
And on and on and on...
并且一直在......
Most JSRs probably have a "EAs would like to be able to..." buried inside somewhere.
大多数JSR可能都有“EAs希望能够......”埋藏在某个地方。
CDI is preferred because it allows apps of large (arbitrary?) horizontal and vertical scales to share contexts, dependencies, and therefore data.
CDI是首选,因为它允许大(任意?)水平和垂直比例的应用程序共享上下文,依赖项,因此共享数据。
In Fowler's words:
用福勒的话来说:
"The problem is how can I make that link so that my lister class is ignorant of the implementation class, but can still talk to an instance to do its work."
“问题是如何建立这个链接,以便我的列表类不知道实现类,但仍然可以与实例通信来完成它的工作。”
" But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments."
“但是如果我们希望以不同的方式部署这个系统,我们需要使用插件来处理与这些服务的交互,这样我们就可以在不同的部署中使用不同的实现。”
"The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister."
“这些容器使用的方法是确保插件的任何用户遵循一些允许单独的汇编程序模块将实现注入列表器的约定。”
In a nutshell, they allow for centralized "command and control" of complex enterprise applications. Java EE is a systematized, reliable process for abstraction and CDI is a an incarnation of it that works so well, it almost makes it invisible. It makes the stitching together of complex apps almost trivial.
简而言之,它们允许对复杂的企业应用程序进行集中的“命令和控制”。 Java EE是一个系统化,可靠的抽象过程,CDI是它的化身,它运作良好,几乎使它看不见。它使复杂应用程序的拼接几乎是微不足道的。
Two more things:
还有两件事:
-
Note that CDI exists peacefully alongside the "service locator pattern", known as JNDI in Java EE, which is preferable if the client developer will need to choose among many identically-typed alternatives.
请注意,CDI与“服务定位器模式”(Java EE中称为JNDI)并行存在,如果客户端开发人员需要在许多相同类型的替代方案中进行选择,则更为可取。
-
CDI is more firepower than is needed in many cases, especially non-enterprise (literally) cases.
CDI比许多情况下需要的火力更强,特别是非企业(字面意思)的情况。