Discussions

News: Getter-based Dependency Injection

  1. Getter-based Dependency Injection (33 messages)

    You have probably heard of setter, and constructor-based dependency injection. Bob Lee implemented a proof of concept using his dynaop framework, and has written all about it.
    Like service locators, dependency injection containers save you from implementing the same dynamic loading and configuration code over and over in different ways; you can configure your entire application consistently in one place. Unlike service locators, dependency injection containers don't require component dependence on a service locator API which facilitates sharing between teams that may have their own service locators.

    Cedric and I chatted last week about his "useless methods" blog and the benefits of getter-based dependency injection over setter or constructor-based injection (a la pico container and Spring). Cedric compares CMP entity beans with theoretical getter-based containers which extend classes at runtime and override getter methods to return injected dependencies. The overridden getters may be bean-style (for easier testing) or abstract (for a cleaner, field free implementation). Such a framework would not require classes to declare setter methods, constructors or fields. Getter injection better enables the container to lazy load dependencies and simplifies injecting different dependencies of the same type.

    I implemented a simple proof of concept using dynaop which you can find in the dynaop.aspects.ioc package in the aspects directory in CVS. The API consists of a single class Container. The Container.add() methods configure new components. For each component, you specify an implementation class, an optional ID, and optional constructor arguments. You can look up component instances from the container by type or ID with the Container.get() methods. The container overrides component instances' getter methods. The container first looks for a component with an ID that matches the getter method's name; for example, an abstract method getCustomerDataSource() returns an instance of a component with the ID "customerDataSource". If the container can't find a component with a matching ID, it next looks for the first component that implements the method's return type. Finally, if the container still can't find a match, it does not override the method.
    Read Bob Lee in Getter-based Dependency Injection

    Threaded Messages (33)

  2. Dependency injection mania[ Go to top ]

    Dependency injection mania continues...
  3. Tapestry properties[ Go to top ]

    This looks a lot like Tapestry's properties. The only difference is that using tapestry, page or component properties are declared in the specification, and their values are not automatically injected from some context. Abstract getters is a good IDEA, and I hope that some mainstream bean container (like Spring) implements this.

    Anyway just for reference, here's what I do today with Tapestry:

    <page-specification class="com.myco.MyPage">
      <property-specification name="myDependency" type="com.myco.MyDependency">
        global.appContext.getBean("myDependency")
      </property-specification>
    </page-specification>

    This is actually documented in Spring's documentation, in a dedicated chapter to Tapestry integration. The <property-specification> declares a property for the current page, and the element value is it's initial value. Here, the value is looked up from a Spring context, stored in the application global object.

    You can declare only the methods you'll need on the MyPage class: if you'll be getting the property value (most likely), just declare an abstract getter and Tapestry will implement it at runtime. If you need to set the property value (not so likely), just declare an abstract setter and Tapastry will implement it.

    I just love this thing. However, I can only use this in Tapestry pages and compenents -- I'd love to do something similar for my business objects.
  4. Tapestry properties[ Go to top ]

    I don't know ... to my mind, one of the big advantages of IOC/Injection is that it allows for easier out-of-container testing. If you use abstract getters for injection, it means that all of your components must be defined as abstract classes. You won't be able to test them without (a) using your container or (b) defining lots of mock objects.

    There are other problems with abstract component classes. If your component class is a concrete class, your compiler will catch mistakes like incorrectly overriding a method in an interface (say, by misspelling the method name). If your components are abstract, you have to keep track of this stuff manually. Also, subclassing your components becomes more complicated (which abstract methods need to be overridden, which one should be left alone?).

    Personally, I would rather live with the extra setters in order to get a concrete class.
  5. I don't know ... to my mind, one of the big advantages
    > of IOC/Injection is that it allows for easier
    > out-of-container testing.

    Exactly. There is nothing wrong with people experimenting with different ways of using IoC, so this seems like a nice research project. However I prefer having a working object that doesn't require any runtime enhancement to be usable.

    Andrus
  6. Inversion of Control is not the same as Dependency Injection,
    whell every type of DI is a kind of IoC, but not every kind of IoC is a type of DI,
    lets explain this,

    the pattern "template method" is one type of Inversion of Control (which was born in the GoF book if I'm not wrong)
    but a template method is not a kind of DI :-)

    I think this puts things clearer :-)

    EOF :-)


    PS.: Portuguese speachers see my Blog: http://www.javablogs.com.br/blogs/page/urubatan
  7. IoC != Dependency Injection[ Go to top ]

    Inversion of Control is not the same as Dependency Injection,whell every type of DI is a kind of IoC, but not every kind of IoC is a type of DI,lets explain this,the pattern "template method" is one type of Inversion of Control (which was born in the GoF book if I'm not wrong)but a template method is not a kind of DI
    Good point. Perhaps I should have called this "Dynamic Templates."
  8. IoC != Dependency Injection[ Go to top ]

    I don't think in this way...

    The DI pattern is a special case of template method (using inheritance) or strategy (using composition) focused in objects association configuration(oac). This type of *special use* already happens in GoF pattern Factory Method. The Factory Method is a type of Template Method used to create objects.

    It is all about callback methods.

    <Rodrigo>
    the pattern "template method" is one type of Inversion of Control (which was born in the GoF book if I'm not wrong)
    but a template method is not a kind of DI :-)
    </Rodrigo>

    I think the correct sentence is: Template method is a way to implement IoC and DI is a special type of IoC used in oac, such as Factory Method is a type of IoC (maybe implemented using a Template Method).

    Regards,

    Forte
  9. However I prefer having a working object that doesn't require any runtime enhancement to be usable.Andrus
    I don't understand this comment. If the object was so simple that it didn't have any external dependencies then it wouldn't need Dependency Injection or a ServiceLocator. But for objects that do, Dependency Injection seems to have some advantages over ServiceLocator: Easier testing, component reuse, and centralized config.
  10. The comment refers to the way supposed getter injection is implemented. A quote from the original post:

    "Cedric compares CMP entity beans with theoretical getter-based containers which extend classes at runtime and override getter methods to return injected dependencies. The overridden getters may be bean-style (for easier testing) or abstract (for a cleaner, field free implementation). Such a framework would not require classes to declare setter methods, constructors or fields. Getter injection better enables the container to lazy load dependencies and simplifies injecting different dependencies of the same type."

    The classes written specifically for the "getter injection" container will be unusable outside of this container, as they there is no *Java* way to initialize them. This is definitely a step back from say Spring, and among other things impedes unit testing as pointed out in the parent post.

    But then again - nothing would prevent developers from creating setters, even if they are not required by the framework. So I guess there is a way around.

    Andrus
  11. Yes ... it is funny to see how quickly the pattern name has changed from "Inversion of Control" to "Dependency Injection" just because Fowler called it that way! (ROFL)
  12. Dependency injection mania[ Go to top ]

    Yes ... it is funny to see how quickly the pattern name has changed from "Inversion of Control" to "Dependency Injection" just because Fowler called it that way! (ROFL)
    I also find it funny that such a funky name matches such a simple concept (both in implementation, use, and understanding). IMO, one of the reasons IoC is so hot right now because it is (a) easy to understand (b) trivial to implement. So basically anybody with any coding skill can comment on it or implement it.

    Anyways, I look forward to reading Bob's blog and hope to come back soon to comment more when I have a chance.
  13. Yes ... it is funny to see how quickly the pattern name has changed from "Inversion of Control" to "Dependency Injection" just because Fowler called it that way! (ROFL)
    Before publishing that article, Martin actually consulted the key Pico guys (Aslak and Paul) and myself, as well as some others. Martin originally coined a slightly different name. Although I was at first a bit doubtful about the idea of a renaming, when Aslak and Paul and I talked through it we could see the value of such a name. The 3 of us agreed on the final name "Dependency Injection" and Martin agreed to use that, instead of his original suggestion, in the article.

    I regard Dependency Injection as a kind of IoC. The IoC term is still useful.

    Regards
    Rod
  14. circular dependancies?[ Go to top ]

    Bob,
    How does the "Container" handle the circular dependancies if it exists?

    tony
    Pleateau.com
  15. circular dependancies?[ Go to top ]

    Bob,How does the "Container" handle the circular dependancies if it exists?tonyPleateau.com
    The simple implementation I present doesn't. It creates a new instance for each relationship (i.e. a.getB().getA() != a). A real container could identify circular situations and look up an existing instance.
  16. This is useful mechanism in some cases. Something similar is coming to Spring fairly soon, probably a couple of weeks or so. Rod wrote some code a while ago, but it's waiting for somebody to polish it up a bit.

    http://article.gmane.org/gmane.comp.java.springframework.devel/4260/match=prototype+handling+support

    What hasn't been mentioned in either Bob's blog entry or this TSS thread (unless I missed it), is that this is a very nice way to handle the situation where a singleton bean coming out of a container, needs to have dependencies populated in it which are themselves not singletons in terms of usage. So if I have a singleton 'PackagingService' coming out of a container, but it needs to work with a non-singleton (also called prototype) service as one of its dependencies, for example an 'EmailService', normal setter dependency injection has issues, because even if the EmailService bean was declared as a prototype in the container, the emailService property on the singleton PackagingService would only be set once, and the PackagingService would always work with the same instance of EmailService.

    The traditional way to handle this is to create a factory interface for getting an email service, and populate that as a dependency into the PackagingService instance.

    With the 'getter' based dependency injection, the container can modify the abstract 'getEmailService' or 'createEmailService' method to automatically return a new non-singleton/protype instance on each invocation.

    Somebody else mentioned the difficulty of unit testing beans with abstract getters. While it is a bit more work, it is manageable by using a subclass in the unit test which actually implements the method.

    Regards,
    Colin
  17. This has been a big complaint in Tapestry ... abstract classes are just harder to test.

    I just blogged about a utility class I've created for use in unit tests that instantiates abstract classes by creating a subclass on the fly.
  18. This is useful mechanism in some cases. Something similar is coming to Spring fairly soon, probably a couple of weeks or so. Rod wrote some code a while ago, but it's waiting for somebody to polish it up a bit.http://article.gmane.org/gmane.comp.java.springframework.devel/4260/match=prototype+handling+supportWhat hasn't been mentioned in either Bob's blog entry or this TSS thread (unless I missed it), is that this is a very nice way to handle the situation where a singleton bean coming out of a container, needs to have dependencies populated in it which are themselves not singletons in terms of usage. So if I have a singleton 'PackagingService' coming out of a container, but it needs to work with a non-singleton (also called prototype) service as one of its dependencies, for example an 'EmailService', normal setter dependency injection has issues, because even if the EmailService bean was declared as a prototype in the container, the emailService property on the singleton PackagingService would only be set once, and the PackagingService would always work with the same instance of EmailService.The traditional way to handle this is to create a factory interface for getting an email service, and populate that as a dependency into the PackagingService instance.With the 'getter' based dependency injection, the container can modify the abstract 'getEmailService' or 'createEmailService' method to automatically return a new non-singleton/protype instance on each invocation.
    with any type of dependecy injection this is possible. Any serious container
    will not inject directly component istances but component connectors. In your example connector can contain ThredLocal instance of EmailService or some context dependend instance (e.g which was selected based on your security permission or some other more complex criteria).
    Somebody else mentioned the difficulty of unit testing beans with abstract getters. While it is a bit more work, it is manageable by using a subclass in the unit test which actually implements the method.Regards,Colin
    Definitly!

    But I don't think that such difficulty at all exists. Simply people who complain about it haven't yet seen how easly some containers can be used inside test case code.
    The statement "classes which need container to run are difficult to test"
    is completly false.

    Getter-based Dependecy Injection is completly valid and components which
    are written accordingly to this contract still can be very easly tested.


    I just don't think that it is any better then field-based dependecy injection as this type of dependecy injection is not requiring any abtract methods or classes.

    also:
    public abstract Kissable getKissable();

    can be change to

    private abstract Kissable getKissable();

    so component implementation is not required to "export" any methods which are the part of component internals.
    In fact setter based dependecy injection whcih uses public methods has the same "feature". If this is a problem or not it depenends on interpretation.
    Some OOP purists might say that this breakes encasulation and is a bad thing.


    Michal
  19. Getter-based Dependency Injection[ Go to top ]

    With the new code generation libraries like Javassist and CGLIB something like this is butt-simple to implement. FYI, Bob's example does not require abstract methods. You can implement the getter if you so desire, the container is just going to extend and reimplement the getter.

    I think this is an interesting approach, but what I like about using AOP over something like this is that there is NO REQUIREMENT for a container. Intercepting a constructor or a field access with AOP allows you to plug in any mechanism you wanted to resolve a dependency(factory, JMX MBean Server, JNDI, CosNaming, LDAP, etc...). Also, this container approach gives you no mechanism to inject context/thread based dependencies, i.e. a security context, where an aspect hooked onto field access could.

    Bill
  20. Also, this container approach gives you no mechanism to inject context/thread based dependencies, i.e. a security context, where an aspect hooked onto field access could.Bill
    Did you ever heard about connectors?! I thought that jboss makes extenisve use of dynamic proxies and this is what you are already been doing! :)

    Michal
  21. Also, this container approach gives you no mechanism to inject context/thread based dependencies, i.e. a security context, where an aspect hooked onto field access could.Bill
    Did you ever heard about connectors?! I thought that jboss makes extenisve use of dynamic proxies and this is what you are already been doing! :)Michal
    Duh! Sorry, my bad. Thanks for pointing it out...
  22. I believe that getter based DI superflous when using AOP to inject dependencies. Dependencies are implementation specifics. IMHO, They do not belong in the public interface of a class.

    Field (private) based DI are much better. It's easily done using AOP and it does not pollute the public interface of an object with implementation details.

    Documentation of the injection can be done (and proper pointcut definitions) by using annotation like it was discussed in this thread.


    Emmanuel.
  23. I believe that getter based DI superflous when using AOP to inject dependencies. Dependencies are implementation specifics. IMHO, They do not belong in the public interface of a class.
    Field (private) based DI are much better. It's easily done using AOP and it does not pollute the public interface of an object with implementation details.Documentation of the injection can be done (and proper pointcut definitions) by using annotation like it was discussed in this thread.Emmanuel.
    I agree that field based DI is at least as good as getter based DI.
    But why to use AOP for that?
    The code which phisically assignes dependecies to private fields
    in pure Java takes no more then 50 lines of code and probably can be even much shorter. And it is something super simple. Code for AOP based solution will be approx. as long. I really feel that often people are searching for possibilties of using AOP just becouse
    ... they want to use AOP and are not even thinking how traditional techniques
    can serve in such situtations. Sometimes they are as good or even better.
    And this is imo such case.

    Michal
  24. I really feel that often people are searching for possibilties of using AOP just becouse ... they want to use AOP and are not even thinking how traditional techniques can serve in such situtations. Sometimes they are as good or even better. And this is imo such case.Michal
    I don't think that is the case here.

    AOP just gives you more possibilities and frees you from being dependent on a container to inject your dependencies. That is why it is an interesting approach.

    I actually do not see any AOP going on in Bob's approach. Just a cool way of using dynamic class creation to implemet the getters.
  25. I really feel that often people are searching for possibilties of using AOP just becouse ... they want to use AOP and are not even thinking how traditional techniques can serve in such situtations. Sometimes they are as good or even better. And this is imo such case.Michal
    I don't think that is the case here. AOP just gives you more possibilities and frees you from being dependent on a container to inject your dependencies. That is why it is an interesting approach.I actually do not see any AOP going on in Bob's approach. Just a cool way of using dynamic class creation to implemet the getters.
    Sorry but you lost me.

    How possibly you can use the class

    abstract Foo
    {
        abstract getBaa();

        ...
    }

    without the container?

    and where do you want to use AOP then if not in container?


    How conatiner will inject dependecies is competly not importand for
    componet devlopers and componet deployers.
    EJB 2.x are not that far from that model and implementations of spec are quite
    different.

    IMO this type of dependecy injection which is disussed in this thread is really quite extream in its requirement for container and such classes/components cannot exist witout the container.
    I do belive that such approch is comptetly valid as I am big fan of containers I am using them pratically everytime and I am really against the way of thinking which assumes that classes should be usable inside and oustide containers. If somebody wants to write classes which are not dependent on a container he is free to do this but in reality it takes from him a lot of power and simplicity which is major profit of component oriented development.




    Michal
  26. I believe that getter based DI superflous when using AOP to inject dependencies. Dependencies are implementation specifics. IMHO, They do not belong in the public interface of a class. Field (private) based DI are much better. It's easily done using AOP and it does not pollute the public interface of an object with implementation details.
    The getters may be protected or even package-private. Intercepting field access is a little too much magic for me.
  27. I believe that getter based DI superflous when using AOP to inject dependencies. Dependencies are implementation specifics. IMHO, They do not belong in the public interface of a class. Field (private) based DI are much better. It's easily done using AOP and it does not pollute the public interface of an object with implementation details.
    The getters may be protected or even package-private. Intercepting field access is a little too much magic for me.
    Dynamically creating a class that implements all these getter methods is just as "magical", if not more so if you measure the amount of bytecode generated. Intercepting field access is all part of a fully-featured AOP implementation.
  28. Dynamically creating a class that implements all these getter methods is just as "magical", if not more so if you measure the amount of bytecode generated. Intercepting field access is all part of a fully-featured AOP implementation.
    No, it's not. With an abstract method, it's clear that someone will extend my class and provide an implementation. Whether that subclass is manually coded or dynamically generated is irrelevant. I don't usually expect some external actor to interfere with my accessing a private field.
  29. Dynamically creating a class that implements all these getter methods is just as "magical", if not more so if you measure the amount of bytecode generated. Intercepting field access is all part of a fully-featured AOP implementation.
    No, it's not. With an abstract method, it's clear that someone will extend my class and provide an implementation. Whether that subclass is manually coded or dynamically generated is irrelevant. I don't usually expect some external actor to interfere with my accessing a private field.
    If you want to make it clear with AOP that it may be injected, use an annotation to make it clearer:

    @Injected Kissable myField;

    or

    /**
     * For JDK 1.4 users
     *
     * @Injected
     */
    Kissable myField;

    pointcut: get(Kissable *->@Injected)

    you could do the same with constructor or setter access as well. It is the same kind of hint that your abstract gives you, but a bit more clear to the developer( well, I should rather say, more clear to the maintainer of the code).


    On Performance:
    AspectJ, JBossAOP, and AspectWerkz, all kick the crap out of dynamic proxy based solutions as far as performance goes.
    The implementation performs just fine. Micro benchmarks are irrelevant. Besides, last I checked dynaop (which uses dynamic proxies) outperformed JBossAOP, and unlike the three tools you mention, dynaop runs perfectly in any environment without custom tools or hooks.
    I think you need to rerun your numbers as JBoss AOP, AspectWerkz, and AspectJ have all gone through multiple releases since the benchmarks you posted on your initial release of dynaop.

    Also, I don't knock the Dynamic Proxy approach. It is a good approach, but not always a complete one and not always as transparent to the user as you would like.

    Bill
  30. @Injected Kissable myField;
    I agree, that is more expressive.
  31. how to cache?[ Go to top ]

    With this approach, don't you have to do additional bytecode enhancements to the subclass to avoid delegating to the container for every get? Even with the concurrent package, having the container as a shared resource ain't such a hot idea.

    Bill
  32. how to cache?[ Go to top ]

    With this approach, don't you have to do additional bytecode enhancements to the subclass to avoid delegating to the container for every get? Even with the concurrent package, having the container as a shared resource ain't such a hot idea.Bill
    It uses a per-instance interceptor which keeps a reference to the component after the first invocation.
  33. how to cache?[ Go to top ]

    With this approach, don't you have to do additional bytecode enhancements to the subclass to avoid delegating to the container for every get? Even with the concurrent package, having the container as a shared resource ain't such a hot idea.Bill
    It uses a per-instance interceptor which keeps a reference to the component after the first invocation.
    If you're using an interceptor, I don't see how you can claim better performance than a AOP based solution. AspectJ, JBossAOP, and AspectWerkz, all kick the crap out of dynamic proxy based solutions as far as performance goes.
  34. how to cache?[ Go to top ]

    AspectJ, JBossAOP, and AspectWerkz, all kick the crap out of dynamic proxy based solutions as far as performance goes.
    The implementation performs just fine. Micro benchmarks are irrelevant. Besides, last I checked dynaop (which uses dynamic proxies) outperformed JBossAOP, and unlike the three tools you mention, dynaop runs perfectly in any environment without custom tools or hooks.