xml 依赖注入容器有什么好处?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/131975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are the benefits of dependency injection containers?
提问by Pavel Feldman
I understand benefits of dependency injection itself. Let's take Spring for instance. I also understand benefits of other Spring featureslike AOP, helpers of different kinds, etc. I'm just wondering, what are the benefits of XML configuration such as:
我了解依赖注入本身的好处。让我们以Spring为例。我也了解其他 Spring 功能(如 AOP、不同类型的助手等)的好处。我只是想知道 XML 配置的好处是什么,例如:
<bean id="Mary" class="foo.bar.Female">
<property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
<property name="girlfriend" ref="Mary"/>
</bean>
compared to plain old java code such as:
与普通的旧 Java 代码相比,例如:
Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);
which is easier debugged, compile time checked and can be understood by anyone who knows only java. So what is the main purpose of a dependency injection framework? (or a piece of code that shows its benefits.)
这更容易调试,编译时检查,任何只知道java的人都可以理解。那么依赖注入框架的主要目的是什么?(或一段显示其好处的代码。)
UPDATE:
In case of
更新:
如果
IService myService;// ...
public void doSomething() {
myService.fetchData();
}
How can IoC framework guess which implementation of myService I want to be injected if there is more than one? If there is only one implementation of given interface, and I let IoC container automatically decide to use it, it will be broken after a second implementation appears. And if there is intentionally only one possible implementation of an interface then you do not need to inject it.
如果有多个,IoC 框架如何猜测我想注入哪个 myService 实现?如果给定的接口只有一个实现,而我让 IoC 容器自动决定使用它,它会在出现第二个实现后被破坏。如果有意只有一种可能的接口实现,则不需要注入它。
It would be really interesting to see small piece of configuration for IoC which shows it's benefits. I've been using Spring for a while and I can not provide such example. And I can show single lines which demonstrate benefits of hibernate, dwr, and other frameworks which I use.
看到 IoC 的一小部分配置显示它的好处会非常有趣。我已经使用 Spring 一段时间了,我无法提供这样的例子。我可以用单行代码展示我使用的 hibernate、dwr 和其他框架的好处。
UPDATE 2:
I realize that IoC configuration can be changed without recompiling. Is it really such a good idea? I can understand when someone wants to change DB credentials without recompiling - he may be not developer. In your practice, how often someone else other than developer changes IoC configuration? I think that for developers there is no effort to recompile that particular class instead of changing configuration. And for non-developer you would probably want to make his life easier and provide some simpler configuration file.
更新 2:
我意识到无需重新编译即可更改 IoC 配置。这真的是个好主意吗?我可以理解何时有人想在不重新编译的情况下更改数据库凭据 - 他可能不是开发人员。在您的实践中,除开发人员之外的其他人多久更改 IoC 配置?我认为对于开发人员来说,无需重新编译该特定类,而无需更改配置。对于非开发人员,您可能希望让他的生活更轻松并提供一些更简单的配置文件。
UPDATE 3:
更新 3:
External configuration of mapping between interfaces and their concrete implementations
接口及其具体实现之间映射的外部配置
What is so good in making it extenal? You don't make all your code external, while you definitely can - just place it in ClassName.java.txt file, read and compile manually on the fly - wow, you avoided recompiling. Why should compiling be avoided?!
有什么好处可以使它外部化?您不会将所有代码都放在外部,但您绝对可以 - 只需将它放在 ClassName.java.txt 文件中,即时手动读取和编译 - 哇,您避免了重新编译。为什么要避免编译?!
You save coding time because you provide mappings declaratively, not in a procedural code
您可以节省编码时间,因为您以声明方式提供映射,而不是在程序代码中
I understand that sometimes declarative approach saves time. For example, I declare only once a mapping between a bean property and a DB column and hibernate uses this mapping while loading, saving, building SQL based on HSQL, etc. This is where the declarative approach works. In case of Spring (in my example), declaration had more lines and had the same expressiveness as corresponding code. If there is an example when such declaration is shorter than code - I would like to see it.
我知道有时声明式方法可以节省时间。例如,我只声明一次 bean 属性和 DB 列之间的映射,并且 hibernate 在加载、保存、基于 HSQL 构建 SQL 等时使用此映射。这就是声明式方法起作用的地方。在 Spring 的情况下(在我的例子中),声明有更多的行并且与相应的代码具有相同的表现力。如果有这样的声明比代码短的例子 - 我想看看它。
Inversion of Control principle allows for easy unit testing because you can replace real implementations with fake ones (like replacing SQL database with an in-memory one)
控制反转原则允许轻松进行单元测试,因为您可以用虚假的实现替换真实的实现(例如用内存中的替换 SQL 数据库)
I do understand inversion of control benefits (I prefer to call the design pattern discussed here as Dependency Injection, because IoC is more general - there are many kinds of control, and we are inverting only one of them - control of initialization). I was asking why someone ever needs something other than a programming language for it. I definitely can replace real implementations with fake ones using code. And this code will express same thing as configuration - it will just initialize fields with fake values.
我确实理解控制反转的好处(我更喜欢将这里讨论的设计模式称为依赖注入,因为 IoC 更通用——有很多种控制,我们只反转其中一种——初始化控制)。我在问为什么有人需要编程语言以外的东西。我绝对可以使用代码用假实现替换真实实现。这段代码将表达与配置相同的东西——它只会用假值初始化字段。
mary = new FakeFemale();
I do understand benefits of DI. I do not understand what benefits are added by external XML configuration compared to configuring code that does the same. I do not think that compiling should be avoided - I compile every day and I'm still alive. I think configuration of DI is bad example of declarative approach. Declaration can be useful if is declared once AND is used many times in different ways - like hibernate cfg, where mapping between bean property and DB column is used for saving, loading, building search queries, etc. Spring DI configuration can be easily translated to configuring code, like in the beginning of this question, can it not? And it is used only for bean initialization, isn't it? Which means a declarative approach does not add anything here, does it?
我确实了解 DI 的好处。我不明白与配置相同的代码相比,外部 XML 配置增加了哪些好处。我不认为应该避免编译——我每天都在编译而且我还活着。我认为 DI 的配置是声明式方法的坏例子。如果声明一次并且以不同方式多次使用,则声明可能很有用 - 例如 hibernate cfg,其中 bean 属性和 DB 列之间的映射用于保存、加载、构建搜索查询等。Spring DI 配置可以轻松转换为配置代码,就像这个问题的开头一样,可以吗?而且它只用于 bean 初始化,不是吗?这意味着声明式方法不会在这里添加任何内容,是吗?
When I declare hibernate mapping, I just give hibernate some information, and it works based on it - I do not tell it what to do. In case of spring, my declaration tells spring exactly wht to do - so why declare it, why not just do it?
当我声明 hibernate 映射时,我只是给 hibernate 一些信息,它基于它工作 - 我没有告诉它做什么。在 spring 的情况下,我的声明告诉 spring 到底要做什么 - 那么为什么要声明它,为什么不直接做呢?
LAST UPDATE:
Guys, a lot of answers are telling me about dependency injection, which I KNOW IS GOOD.
The question is about purpose of DI configuration instead of initializing code - I tend to think that initializing code is shorter and clearer.
The only answer I got so far to my question, is that it avoids recompiling, when the configuration changes. I guess I should post another question, because it is a big secret for me, why compiling should be avoided in this case.
最后更新:
伙计们,很多答案都在告诉我关于依赖注入的问题,我知道这很好。问题是关于 DI 配置的目的而不是初始化代码 - 我倾向于认为初始化代码更短更清晰。到目前为止,我对我的问题的唯一答案是,当配置更改时,它可以避免重新编译。我想我应该发布另一个问题,因为这对我来说是一个很大的秘密,为什么在这种情况下应该避免编译。
采纳答案by Pavel Feldman
For myself one of the main reasons to use an IoC (and make use of external configuration) is around the two areas of:
对我自己来说,使用 IoC(并利用外部配置)的主要原因之一是围绕以下两个方面:
- Testing
- Production maintenance
- 测试
- 生产维护
Testing
测试
If you split your testing into 3 scenarios (which is fairly normal in large scale development):
如果您将测试分成 3 个场景(这在大规模开发中是相当正常的):
- Unit testing
- Integration testing
- Black box testing
- 单元测试
- 集成测试
- 黑盒测试
What you will want to do is for the last two test scenarios (Integration & Black box), is not recompile any part of the application.
对于最后两个测试场景(集成和黑盒),您要做的是不重新编译应用程序的任何部分。
If any of your test scenarios require you to change the configuration (ie: use another component to mimic a banking integration, or do a performance load), this can be easily handled (this does come under the benefits of configuring the DI side of an IoC though.
如果您的任何测试场景需要您更改配置(即:使用另一个组件来模拟银行集成,或执行性能负载),则可以轻松处理(这确实属于配置 DI 端的好处)国际奥委会虽然。
Additionally if your app is used either at multiple sites (with different server and component configuration) or has a changing configuration on the live environment you can use the later stages of testing to verify that the app will handle those changes.
此外,如果您的应用程序用于多个站点(具有不同的服务器和组件配置)或在实时环境中具有不断变化的配置,您可以使用测试的后期阶段来验证该应用程序将处理这些更改。
Production
生产
As a developer you don't (and should not) have control of the production environment (in particular when your app is being distributed to multiple customers or seperate sites), this to me is the real benefit of using both an IoC and external configuration, as it is up to the infrastructure/production support to tweak and adjust the live environment without having to go back to developers and through test (higher cost when all they want to do is move a component).
作为开发人员,您没有(也不应该)控制生产环境(特别是当您的应用程序分发给多个客户或单独的站点时),这对我来说是同时使用 IoC 和外部配置的真正好处,因为这取决于基础设施/生产支持来调整和调整实时环境,而无需返回给开发人员并通过测试(当他们想做的只是移动组件时,成本更高)。
Summary
概括
The main benefits that external configuration of an IoC come from giving others (non-developers) the power to configure your application, in my experience this is only useful under a limited set of circumstances:
IoC 的外部配置的主要好处是让其他人(非开发人员)能够配置您的应用程序,根据我的经验,这仅在有限的情况下有用:
- Application is distributed to multiple sites/clients where environments will differ.
- Limited development control/input over the production environment and setup.
- Testing scenarios.
- 应用程序分发到环境不同的多个站点/客户端。
- 对生产环境和设置的有限开发控制/输入。
- 测试场景。
In practice I've found that even when developing something that you do have control over the environment it will be run on, over time it is better to give someone else the capabilities to change the configuration:
在实践中,我发现即使在开发一些你可以控制它运行的环境时,随着时间的推移,最好给其他人更改配置的能力:
- When developing you don't know when it will change (the app is so useful your company sells it to someone else).
- I don't want to be stuck with changing the code every time a slight change is requested that could have been handled by setting up and using a good configuration model.
- 在开发时,您不知道它何时会发生变化(该应用程序非常有用,您的公司会将其出售给其他人)。
- 我不想在每次请求稍作更改时都必须更改代码,而这些更改本可以通过设置和使用良好的配置模型来处理。
Note: Application refers to the complete solution (not just the executable), so all files required for the application to run.
注意:应用程序是指完整的解决方案(不仅仅是可执行文件),因此应用程序运行所需的所有文件。
回答by Kevin S.
Dependency injection is a coding style that has its roots in the observation that object delegation is usually a more useful design pattern than object inheritance (i.e., the object has-a relationship is more useful than the object is-a relationship). One other ingredient is necessary however for DI to work, that of creating object interfaces. Combining these two powerful design patterns software engineers quickly realized that they could create flexible loosely coupled code and thus the concept of Dependency Injection was born. However it wasn't until object reflection became available in certain high level languages that DI really took off. The reflection component is core to most of today's DI systems today because the really cool aspects of DI require the ability to programmatically select objects and configure and inject them into other objects using a system external and independent to the objects themselves.
依赖注入是一种编码风格,其根源在于对象委托通常是比对象继承更有用的设计模式(即,对象具有-关系比对象是-关系更有用)。然而,DI 工作还需要另一种成分,即创建对象接口。结合这两种强大的设计模式,软件工程师很快意识到他们可以创建灵活的松耦合代码,因此依赖注入的概念诞生了。然而,直到对象反射在某些高级语言中可用,DI 才真正起飞。反射组件是当今大多数人的核心
A language must provide good support for both normal Object Oriented programming techniques as well as support for object interfaces and object reflection (for example Java and C#). While you can build programs using DI patterns in C++ systems its lack of reflection support within the language proper prevents it from supporting application servers and other DI platforms and hence limits the expressiveness of the DI patterns.
一种语言必须为普通的面向对象编程技术以及对对象接口和对象反射(例如 Java 和 C#)的支持提供良好的支持。虽然您可以在 C++ 系统中使用 DI 模式构建程序,但由于语言本身缺乏反射支持,因此无法支持应用服务器和其他 DI 平台,因此限制了 DI 模式的表达能力。
Strengths of a system built using DI patterns:
使用 DI 模式构建的系统的优势:
- DI code is much easier to reuse as the 'depended' functionality is extrapolated into well defined interfaces, allowing separate objects whose configuration is handled by a suitable application platform to be plugged into other objects at will.
- DI code is much easier to test. The functionality expressed by the object can be tested in a black box by building 'mock' objects implementing the interfaces expected by your application logic.
- DI code is more flexible. It is innately loosely coupled code -- to an extreme. This allows the programmer to pick and choose how objects are connected based exclusively on their required interfaces on one end and their expressed interfaces on the other.
- External (Xml) configuration of DI objects means that others can customize your code in unforeseen directions.
- External configuration is also a separation of concern pattern in that all problems of object initialization and object interdependency management can be handled by the application server.
- Note that external configuration is not required to use the DI pattern, for simple interconnections a small builder object is often adequate. There is a tradeoff in flexibility between the two. A builder object is not as flexible an option as an externally visible configuration file. The developer of the DI system must weigh the advantages of flexibility over convenience, taking care that small scale, fine grain control over object construction as expressed in a configuration file may increase confusion and maintenance costs down the line.
- DI 代码更容易重用,因为“依赖”功能被外推到定义良好的接口中,允许将其配置由合适的应用程序平台处理的单独对象随意插入其他对象。
- DI 代码更容易测试。通过构建“模拟”对象来实现应用程序逻辑所期望的接口,可以在黑盒中测试对象所表达的功能。
- DI 代码更灵活。它天生就是松散耦合的代码——到了极致。这允许程序员根据对象在一端所需的接口和在另一端表达的接口来挑选和选择对象的连接方式。
- DI 对象的外部 (Xml) 配置意味着其他人可以在不可预见的方向上自定义您的代码。
- 外部配置也是一种关注点分离模式,因为对象初始化和对象相互依赖管理的所有问题都可以由应用程序服务器处理。
- 请注意,使用 DI 模式不需要外部配置,对于简单的互连,一个小的构建器对象通常就足够了。两者之间的灵活性有一个折衷。构建器对象不像外部可见的配置文件那样灵活。DI 系统的开发人员必须权衡灵活性和便利性的优势,注意对配置文件中表达的对象构造的小规模、细粒度控制可能会增加混乱和维护成本。
Definitely DI code seems more cumbersome, the disadvantages of having all of those XML files that configure objects to be injected into other objects appears difficult. This is, however, the point of DI systems. Your ability to mix and match code objects as a series of configuration settings allows you to build complex systems using 3rd party code with minimal coding on your part.
确实,DI 代码看起来更麻烦,将所有配置对象的 XML 文件注入其他对象的缺点似乎很困难。然而,这正是 DI 系统的重点。您将代码对象作为一系列配置设置进行混合和匹配的能力使您能够使用 3rd 方代码构建复杂的系统,而您只需进行最少的编码。
The example provided in the question merely touches on the surface of the expressive power that a properly factored DI object library can provide. With some practice and a lot of self discipline most DI practitioners find that they can build systems that have 100% test coverage of application code. This one point alone is extraordinary. This is not 100% test coverage of a small application of a few hundred lines of code, but 100% test coverage of applications comprising hundreds of thousands of lines of code. I am at a loss of being able to describe any other design pattern that provides this level of testability.
问题中提供的示例仅涉及适当分解的 DI 对象库可以提供的表达能力的表面。通过一些实践和大量的自律,大多数 DI 从业者发现他们可以构建对应用程序代码具有 100% 测试覆盖率的系统。仅这一点就非同寻常。这不是几百行代码的小应用程序的 100% 测试覆盖率,而是包含数十万行代码的应用程序的 100% 测试覆盖率。我无法描述提供这种可测试性级别的任何其他设计模式。
You are correct in that an application of a mere 10s of lines of code is easier to understand than several objects plus a series of XML configuration files. However as with most powerful design patterns, the gains are found as you continue to add new features to the system.
你是对的,仅仅 10 行代码的应用程序比几个对象加上一系列 XML 配置文件更容易理解。然而,与最强大的设计模式一样,随着您继续向系统添加新功能,就会发现收益。
In short, large scale DI based applications are both easier to debug and easier to understand. While the Xml configuration is not 'compile time checked' all application services that this author is aware of will provide the developer with error messages if they attempt to inject an object having an incompatible interface into another object. And most provide a 'check' feature that covers all known objects configurations. This is easily and quickly done by checking that the to-be-injected object A implements the interface required by object B for all configured object injections.
简而言之,大规模基于 DI 的应用程序既易于调试又易于理解。虽然 Xml 配置不是“编译时检查”,但作者知道的所有应用程序服务都将向开发人员提供错误消息,如果他们试图将具有不兼容接口的对象注入另一个对象。并且大多数都提供涵盖所有已知对象配置的“检查”功能。通过检查要注入的对象 A 是否为所有已配置的对象注入实现了对象 B 所需的接口,可以轻松快速地完成此操作。
回答by Mike Stone
This is a bit of a loaded question, but I tend to agree that huge amounts of xml configuration doesn't really amount to much benefit. I like my applications to be as light on dependencies as possible, including the hefty frameworks.
这是一个有点棘手的问题,但我倾向于同意大量的 xml 配置并没有真正带来多少好处。我喜欢我的应用程序尽可能少依赖,包括庞大的框架。
They simplify the code a lot of the times, but they also have an overhead in complexity that makes tracking down problems rather difficult (I have seen such problems first hand, and straight Java I would be a lot more comfortable dealing with).
它们在很多时候都简化了代码,但它们也有复杂性的开销,这使得跟踪问题变得相当困难(我亲眼见过这样的问题,而直接处理 Java 会更舒服)。
I guess it depends on style a bit, and what you are comfortable with... do you like to fly your own solution and have the benefit of knowing it inside out, or bank on existing solutions that may prove difficult when the configuration isn't just right? It's all a tradeoff.
我想这在某种程度上取决于风格,以及您对什么感到满意......您喜欢使用自己的解决方案并从中受益,还是依靠现有的解决方案,当配置不合适时,这些解决方案可能会证明是困难的?刚刚好?这都是一个权衡。
However, XML configuration is a bit of a pet peeve of mine... I try to avoid it at all costs.
然而,XML 配置有点让我讨厌……我会不惜一切代价避免它。
回答by Bill K
Any time you can change your code to data you're making a step in the right direction.
任何时候您可以将代码更改为数据,您就是在朝着正确的方向迈出一步。
Coding anything as data means that your code itself is more general and reusable. It also means that your data may be specified in a language that fits it exactly.
将任何内容编码为数据意味着您的代码本身更加通用和可重用。这也意味着您的数据可能以完全适合的语言指定。
Also, an XML file can be read into a GUI or some other tool and easily manipulated pragmatically. How would you do that with the code example?
此外,XML 文件可以读入 GUI 或其他一些工具,并可以轻松地进行操作。你会如何用代码示例做到这一点?
I'm constantly factoring things most people would implement as code into data, it makes what code is left MUCH cleaner. I find it inconceivable that people will create a menu in code rather than as data--it should be obvious that doing it in code is just plain wrong because of the boilerplate.
我不断地将大多数人作为代码实现的东西分解为数据,这使得代码变得更加清晰。我发现人们将在代码中而不是数据中创建菜单是不可思议的——很明显,由于样板文件,在代码中创建菜单是完全错误的。
回答by MetroidFan2002
The reason for using a DI container are that you don't have to have a billion properties pre-configured in your code that are simply getters and setters. Do you really want to hardcode all those with new X()? Sure, you can have a default, but the DI container allows the creation of singletons which is extremely easy and allows you to focus on the details of the code, not the miscellaneous task of initializing it.
使用 DI 容器的原因是您不必在代码中预先配置十亿个属性,这些属性只是 getter 和 setter。你真的想用 new X() 对所有这些进行硬编码吗?当然,你可以有一个默认值,但是 DI 容器允许创建单例,这非常容易,并且允许你专注于代码的细节,而不是初始化它的杂项任务。
For example, Spring allows you to implement the InitializingBean interface and add an afterPropertiesSet method (you may also specify an "init-method" to avoid coupling your code to Spring). These methods will allow you to ensure that any interface specified as a field in your class instance is configured correctly upon startup, and then you no longer have to null-check your getters and setters (assuming you do allow your singletons to remain thread-safe).
例如,Spring 允许您实现 InitializingBean 接口并添加 afterPropertiesSet 方法(您也可以指定“init-method”以避免将您的代码耦合到 Spring)。这些方法将允许您确保在启动时正确配置类实例中指定为字段的任何接口,然后您不再需要对 getter 和 setter 进行空检查(假设您确实允许单例保持线程安全)。
Furthermore, it is much easier to do complex initializations with a DI container instead of doing them yourself. For instance, I assist with using XFire (not CeltiXFire, we only use Java 1.4). The app used Spring, but it unfortunately used XFire's services.xml configuration mechanism. When a Collection of elements needed to declare that it had ZERO or more instances instead of ONE or more instances, I had to override some of the provided XFire code for this particular service.
此外,使用 DI 容器进行复杂的初始化比自己进行要容易得多。例如,我协助使用 XFire(不是 CeltiXFire,我们只使用 Java 1.4)。该应用程序使用了 Spring,但不幸的是它使用了 XFire 的 services.xml 配置机制。当一个元素集合需要声明它有零个或多个实例而不是一个或多个实例时,我不得不重写一些为此特定服务提供的 XFire 代码。
There are certain XFire defaults defined in its Spring beans schema. So, if we were using Spring to configure the services, the beans could have been used. Instead, what happened was that I had to supply an instance of a specific class in the services.xml file instead of using the beans. To do this, I needed to provide the constructor and set up the references declared in the XFire configuration. The real change that I needed to make required that I overload a single class.
在其 Spring beans 模式中定义了某些 XFire 默认值。因此,如果我们使用 Spring 来配置服务,则可以使用 bean。相反,发生的情况是我必须在 services.xml 文件中提供特定类的实例,而不是使用 bean。为此,我需要提供构造函数并设置在 XFire 配置中声明的引用。我需要做出的真正改变要求我重载一个类。
But, thanks to the services.xml file, I had to create four new classes, setting their defaults according to their defaults in the Spring configuration files in their constructors. If we had been able to use the Spring configuration, I could have just stated:
但是,多亏了 services.xml 文件,我不得不创建四个新类,根据它们构造函数中 Spring 配置文件中的默认值设置它们的默认值。如果我们能够使用 Spring 配置,我可以说:
<bean id="base" parent="RootXFireBean">
<property name="secondProperty" ref="secondBean" />
</bean>
<bean id="secondBean" parent="secondaryXFireBean">
<property name="firstProperty" ref="thirdBean" />
</bean>
<bean id="thirdBean" parent="thirdXFireBean">
<property name="secondProperty" ref="myNewBean" />
</bean>
<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />
Instead, it looked more like this:
相反,它看起来更像这样:
public class TheFirstPointlessClass extends SomeXFireClass {
public TheFirstPointlessClass() {
setFirstProperty(new TheSecondPointlessClass());
setSecondProperty(new TheThingThatWasHereBefore());
}
}
public class TheSecondPointlessClass extends YetAnotherXFireClass {
public TheSecondPointlessClass() {
setFirstProperty(TheThirdPointlessClass());
}
}
public class TheThirdPointlessClass extends GeeAnotherXFireClass {
public TheThirdPointlessClass() {
setFirstProperty(new AnotherThingThatWasHereBefore());
setSecondProperty(new WowItsActuallyTheCodeThatChanged());
}
}
public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
public WowItsActuallyTheCodeThatChanged() {
}
public overrideTheMethod(Object[] arguments) {
//Do overridden stuff
}
}
So the net result is that four additional, mostly pointless Java classes had to be added to the codebase to achieve the affect that one additional class and some simple dependency container information achieved. This isn't the "exception that proves the rule", this IS the rule...handling quirks in code is much cleaner when the properties are already provided in a DI container and you're simply changing them to suit a special situation, which happens more often than not.
因此,最终结果是必须向代码库中添加四个额外的、几乎毫无意义的 Java 类,以实现通过一个额外的类和一些简单的依赖容器信息实现的效果。这不是“证明规则的例外”,这是规则……当属性已经在 DI 容器中提供并且您只是更改它们以适应特殊情况时,处理代码中的怪癖会更清晰,这种情况经常发生。
回答by badunk
I have your answer
我有你的答案
There are obviously trade offs in each approach, but externalized XML configuration files are useful for enterprise development in which build systems are used to compile the code and not your IDE. Using the build system, you may want to inject certain values into your code - for example the version of the build (which could be painful to have to update manually each time you compile). The pain is greater when your build system pulls code off of some version control system. Modifying simple values at compile time would require you to change a file, commit it, compile, and then revert each time for each change. These aren't changes that you want to commit into your version control.
每种方法显然都存在折衷,但外部化的 XML 配置文件对于使用构建系统而不是您的 IDE 编译代码的企业开发很有用。使用构建系统,您可能希望将某些值注入到您的代码中 - 例如构建的版本(每次编译时必须手动更新可能会很痛苦)。当您的构建系统从某些版本控制系统中提取代码时,痛苦会更大。在编译时修改简单的值需要您更改文件、提交、编译,然后每次更改时都还原。这些不是您想要提交到版本控制中的更改。
Other useful use cases regarding the build system and external configs:
关于构建系统和外部配置的其他有用用例:
- injecting styles/stylesheets for a single code base for different builds
- injecting different sets of dynamic content (or references to them) for your single code base
- injecting localization context for different builds/clients
- changing a webservice URI to a backup server (when the main one goes down)
- 为不同构建的单个代码库注入样式/样式表
- 为您的单个代码库注入不同的动态内容集(或对它们的引用)
- 为不同的构建/客户端注入本地化上下文
- 将 Web 服务 URI 更改为备用服务器(当主服务器出现故障时)
Update: All the above examples were on things that didn't necessarily require dependencies on classes. But you can easily build up cases where both a complex object and automation is necessary - for example:
更新:以上所有示例都针对不一定需要依赖于类的事物。但是您可以轻松构建需要复杂对象和自动化的案例 - 例如:
- Imagine you had a system in which it monitored the traffic of your website. Depending on the # of concurrent users, it turns on/off a logging mechanism. Perhaps while the mechanism is off, a stub object is put in its place.
- Imagine you had a web conferencing system in which depending on the # of users, you want to switch out the ability to do P2P depending on # of participants
- 想象一下,您有一个系统来监控您网站的流量。根据并发用户数,它打开/关闭日志记录机制。也许当机制关闭时,存根对象被放置在它的位置。
- 想象一下,您有一个网络会议系统,根据用户数量,您希望根据参与者数量切换 P2P 功能
回答by aku
You don't need to recompile your code each time you change something in configuration. It will simplify program deployment and maintenance. For example you can swap one component with another with just 1 change in config file.
每次更改配置时都不需要重新编译代码。它将简化程序部署和维护。例如,您只需在配置文件中进行 1 次更改即可将一个组件与另一个组件交换。
回答by Paul Whelan
You can slot in a new implementation for girlfriend. So new female can be injected without recompiling your code.
你可以为女朋友插入一个新的实现。因此,无需重新编译代码即可注入新女性。
<bean id="jane" class="foo.bar.HotFemale">
<property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
<property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
<property name="girlfriend" ref="jane"/>
</bean>
(The above assumes Female and HotFemale implement the same GirlfFriend interface)
(以上假设Female和HotFemale实现相同的GirlfFriend接口)
回答by Romain Verdier
In the .NET world, most of IoC frameworks provide both XML and Code configuration.
在 .NET 世界中,大多数 IoC 框架都提供 XML 和代码配置。
StructureMap and Ninject, for example, use fluent interfaces to configure containers. You are no longer constrained to use XML configuration files. Spring, which also exists in .NET, heavily relies on XML files since it is his historical main configuration interface, but it is still possible to configure containers programmatically.
例如,StructureMap 和 Ninject 使用流畅的接口来配置容器。您不再受限于使用 XML 配置文件。Spring 也存在于 .NET 中,它严重依赖 XML 文件,因为它是他历史上的主要配置接口,但仍然可以通过编程方式配置容器。
回答by David W Crook
From a Spring perspecitve I can give you two answers.
从 Spring 的角度来看,我可以给你两个答案。
First the XML configuration isn't the only way to define the configuration. Most things can be configured using annotations and the things that must be done with XML are configuration for code that you aren't writing anyways, like a connection pool that you are using from a library. Spring 3 includes a method for defining the DI configuration using Java similar to the hand rolled DI configuration in your example. So using Spring does not mean that you have to use an XML based configuration file.
首先,XML 配置不是定义配置的唯一方法。大多数事情都可以使用注释进行配置,而必须使用 XML 完成的事情是配置您无论如何都不会编写的代码,例如您从库中使用的连接池。Spring 3 包含一种使用 Java 定义 DI 配置的方法,类似于示例中的手动 DI 配置。因此,使用 Spring 并不意味着您必须使用基于 XML 的配置文件。
Secondly Spring is a lot more than just a DI framework. It has lots of other features including transaction management and AOP. The Spring XML configuration mixes all these concepts together. Often in the same configuration file I'm specifying bean dependencies, transaction settings and adding session scoped beans that actually handled using AOP in the background. I find the XML configuration provides a better place to manage all these features. I also feel that the annotation based configuration and XML configuration scale up better than doing Java based configuration.
其次,Spring 不仅仅是一个 DI 框架。它还有许多其他功能,包括事务管理和 AOP。Spring XML 配置将所有这些概念混合在一起。通常在同一个配置文件中,我指定 bean 依赖项、事务设置并添加在后台使用 AOP 实际处理的会话范围 bean。我发现 XML 配置提供了一个更好的地方来管理所有这些功能。我也觉得基于注解的配置和 XML 配置比基于 Java 的配置更好地扩展。
But I do see your point and there isn't anything wrong with defining the dependency injection configuration in Java. I normally do that myself in unit tests and when I'm working on a project small enough that I haven't added a DI framework. I don't normally specify configuration in Java because to me that's the kind plumbing code that I'm trying to get away from writing when I chose to use Spring. That's a preference though, it doesn't mean that XML configuration is superior to Java based configuration.
但我确实明白你的意思,在 Java 中定义依赖注入配置没有任何问题。我通常在单元测试中自己做,当我在做一个足够小的项目时,我没有添加 DI 框架。我通常不会在 Java 中指定配置,因为对我来说,这是我在选择使用 Spring 时试图避免编写的那种管道代码。尽管这是一种偏好,但这并不意味着 XML 配置优于基于 Java 的配置。

