What are the benefits of dependency injection containers?

前端 未结 16 2633
南笙
南笙 2020-12-02 04:09

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 kind

相关标签:
16条回答
  • 2020-12-02 05:03

    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.

    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).

    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.

    0 讨论(0)
  • 2020-12-02 05:03

    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.

    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).

    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.

    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.

    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:

    <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.

    0 讨论(0)
  • 2020-12-02 05:05

    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.

    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)

    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
    0 讨论(0)
  • 2020-12-02 05:05

    Ease of combining partial configurations into a final complete configuration.

    For example, in web applications, the model, view and controllers are typically specified in separate configuration files. Use the declarative approach, you can load, for example:

      UI-context.xml
      Model-context.xml
      Controller-context.xml
    

    Or load with a different UI and a few extra controllers:

      AlternateUI-context.xml
      Model-context.xml
      Controller-context.xml
      ControllerAdditions-context.xml
    

    To do the same in code requires an infrastructure for combining partial configurations. Not impossible to do in code, but certainly easier to do using an IoC framework.

    0 讨论(0)
提交回复
热议问题