Blogs

SpringSource Blog

New Improvements in Domain Object Dependency Injection Feature

Ramnivas Laddad

Spring's dependency injection (DI) mechanism allows configuring beans defined in application context. What if you want to extend the same idea to non-beans? Spring's support for domain object DI utilizes AspectJ weaving to extend DI to any object, even if it is created by, say, a web or an ORM framework. This enables creating domain behavior rich objects, since domain objects can now collaborate with the injected objects. In this blog, I discuss the latest improvements in the Spring framework in this area.

The core idea behind domain object DI is quite simple: An AspectJ-woven aspect selects join points corresponding to creation or deserialization of any object matching certain specification. Advice to those join points inject dependencies into the object being created or deserialized. Of course, the devil is in the details. For example, how do you select join point corresponding to deserialization or how do you inject dependency only once per object? By offering a few pre-written aspects, Spring shields developers from all these details.

Currently, most Spring users use the @Configurable annotation to designate the configurable classes. With latest improvements in upcoming Spring 2.5.2, available starting with nightly build 379, you have a few more options making this feature a lot more powerful. The new improvements follow the "Make simple things simple, complex things possible" principle. Depending on your familiarity with AspectJ and expected design sophistication, one of the options will serve well. Figure 1 shows the new aspect hierarchy that makes a combination of simplicity and flexibility possible.

Domain Object Dependency Injection Aspects

Figure 1: Inheritance hierarchy for domain object dependency injection aspects.

So what does each of these aspects offer? Let's go bottom up.

Simple things simple: AnnotationBeanConfigurerAspect

AnnotationBeanConfigurerAspect enables domain object DI without any user AspectJ code. Therefore, it is the easiest choice for many developers. With this aspect, you annotate the classes that need dependency injection with the @Configurable annotation. For example, you can have the Order class annotated as follows:

@Configurable
public class Order {
    private transient MailSender mailSender;

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void process() {
        ...
        mailSender.send(...);
        ...
    }
}

Next, you instruct Spring on how to configure objects of the Order type. The instructions follow the standard bean definition for a prototype bean as follows:

<context:spring-configured/>

<bean class="example.Order" scope="prototype">
    <property name="mailSender" ref="externalMailSender"/>
</bean>

<bean id="externalMailSender" ...>
    ...
</bean>

Now upon any Order creation or deserialization, Spring will set the mailSender property of the created object with the externalMailSender bean.

Spring 2.5 features a new annotation-based configuration option that allows eliminating or reducing the attendant XML. The @Configurable annotation-based DI benefits from it as well. For example, you can mark the mailSender property as @Autowired as follows:

@Configurable
public class Order {
    private transient MailSender mailSender;

    @Autowired
    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void process() {
        ...
        mailSender.send(...);
        ...
    }
}

You can get rid of even the setter by annotating the field itself, reducing the above code to:

@Configurable
public class Order {
    @Autowired private transient MailSender mailSender;

    public void process() {
        ...
        mailSender.send(...);
        ...
    }
}

In either case, the attendant XML configuration reduces to the following (note the use of <context:annotation-config/>):

<context:spring-configured/>

<context:annotation-config/>

<bean id="externalMailSender" ...>
    ...
</bean>

For more details on this domain object DI option, please see Using AspectJ to dependency inject domain objects with Spring.

Complex things possible: AbstractInterfaceDrivenDependencyInjectionAspect

The base aspect of AnnotationBeanConfigurerAspect, AbstractInterfaceDrivenDependencyInjectionAspect, uses an interface instead of annotation to mark a configurable class. While it looks like a rather superficial change, it offers some interesting options such as using domain interfaces and annotations to designate dependency injection, improving performance of injection by bypassing reflection, and utilizing multiple aspects to configure an object.

At the design level, this aspect configures any domain object whose type implements the ConfigurableObject interface. While, having a type implement the ConfigurableObject interface directly is certainly a valid choice, an elegant alternative is to use a declare parents statement in another aspect (a subaspect of AbstractInterfaceDrivenDependencyInjectionAspect would be a logical choice). The statement would declare a configurable class as implementing the ConfigurableObject interface. This keeps your domain classes free from Spring-specific artifacts, while benefiting from the DI mechanism. Let's see an example of such usage.

Consider the Order class from the earlier section. Instead of using the @Configurable, you can let it implement a domain-specific MailSenderClient interface that signifies that it uses a MailSender.

public class Order implements MailSenderClient {
    private transient MailSender mailSender;

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void process() {
        ...
        mailSender.send(...);
        ...
    }
}

Next you write a subaspect of AbstractInterfaceDrivenDependencyInjectionAspect to inject dependencies into any MailSenderClient objects.

public aspect MailClientDependencyInjectionAspect extends
    AbstractInterfaceDrivenDependencyInjectionAspect {
    private MailSender mailSender;

    declare parents: MailSenderClient implements ConfigurableObject;

    public pointcut inConfigurableBean() : within(MailSenderClient+);

    public void configureBean(Object bean) {
        ((MailSenderClient)bean).setMailSender(this.mailSender);
    }

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }
}

There are two AspectJ constructs used in the aspect:

  1. The declare parents statement makes MailSenderClient implement the ConfigurableObject interface, making it eligible for DI through AbstractInterfaceDrivenDependencyInjectionAspect.
  2. The inConfigurableBean() selects join points only in the MailSenderClient's subtype, thus restricting aspect's applicability to only the matching types.

The configureBean() method performs injection into the bean by making direct calls to the appropriate setters. Of course, any other logic appropriate for bean configuration such as calling a multi-argument method or calling any initialization methods would work just fine. Note that direct calls used in this way avoid reflection and can yield noticeable performance improvements if the rate of domain object creation is high.

You need to configure the MailClientDependencyInjectionAspect aspect instance itself to inject its dependency–the mailSender property. The Spring way would be to create a bean for the aspect and configure it in application context:

<bean class="example.MailClientDependencyInjectionAspect"
        factory-method="aspectOf">
    <property name="mailSender" ref="externalMailSender"/>
</bean>

<bean id="externalMailSender" ...>
    ...
</bean>

There are a few additional patterns around this aspect:

  • Using multiple aspects to configure one object (one per "client" interface, for example).
  • Using domain annotation instead of domain interface or the @Configurable annotation to designate a configurable type.
  • Using hasmethod()-based type pattern (currently an experimental feature in AspectJ 5 that will become a regular feature in AspectJ 6) to avoid use of DI related types or annotations.
  • Using AspectJ-based mixins to provide default implementation for the client interfaces and avoid repeated setters.

However, let's save these ideas for another blog entry.

Flexibility when you need it: AbstractDependencyInjectionAspect

Finally, here is the most flexible base aspect. This aspect requires you to have solid understanding of the AspectJ pointcut language. However, except in extreme customization scenario (such as custom deserialization events), you won't directly create a subaspect of this base aspect. Instead, you will use one of the subaspects we discussed earlier.

The aspect declares six pointcuts that a subaspect may define:

  1. beanConstruction(Object bean): Select bean construction. Typical implementation will select object initialization join point.
  2. beanDeserialization(Object bean): Select bean deserialization. Typical implementation will select the readResolve() method that must be present in the injected object. If you are using a nonstandard deserialization (that doesn't invoke readResolve()), you would select an appropriate alternative method with this pointcut.
  3. inConfigurableBean(): Select join points in bean configurable by the defining aspect. Typical implementation will use a within() pointcut with appropriate type pattern.
  4. preConstructionConfiguration(): Select join points for beans that need dependencies injected prior to construction. The default implementation of this pointcut select no join point (beans will have dependencies injected after the constructor has run).
  5. mostSpecificSubTypeConstruction(): Select join points corresponding to the most specific subtype. Default implementation uses join point signature to determine if the constructor represents the most specific in a type hierarchy of the bean being injected. This information is then used in conjunction with the preConstructionConfiguration() pointcut to use a before or after advice for injecting dependencies.
  6. leastSpecificSuperTypeConstruction(): Select join points corresponding to the least specific supertype.

This aspect also defines an abstract method configureBean(Object bean), whose implementation should specify the logic corresponding to dependency injection.

So there you have all options to enable domain object DI in your application. If you are into DDD or otherwise need DI extended to your domain objects, you have to look at these new set of aspects. Depending on your specific needs and AspectJ knowledge, you will find one of them helpful towards creating an elegant solution.

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • Twitter
 

11 responses


  1. Great! I did a presentation a year ago on the Jazoon conference talking exactly about problems with DI and domain objects (and serialization).

    http://jazoon.com/download/presentations/866.pdf

    It's very good to hear that you've implemented exactly what I was proposing back then.


  2. I've been using the @Configurable annotation and AnnotationBeanConfigurerAspect for some time, but the new extension points will be most useful.
    However, when implementing Serializable, we are getting the following messages from the class loader (I am using LTW within the test). I have not tested injection on de-serialisation (which is essential for me) as yet.

    ClassLoader@92e78c] error at example\Order.java::0 The type example.Order must implement the inherited abstract method org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport.readResolve()
    see also: org\springframework\beans\factory\aspectj\AbstractInterfaceDrivenDependencyInjectionAspect.aj::0
    see also: org\springframework\beans\factory\aspectj\opt\j2ee\domains\springframework.org\build\bamboo-home\xml-data\build-dir\SPR-NIGHTLY\spring\aspectj\src\org\springframework\beans\factory\aspectj\AnnotationBeanConfigurerAspect.aj:87::0
    [AppClassLoader@92e78c] weaveinfo Extending interface set for type 'example.Order' (Order.java) to include 'org.springframework.beans.factory.aspectj.ConfigurableObject' (AnnotationBeanConfigurerAspect.aj)
    [AppClassLoader@92e78c] weaveinfo Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.())' in Type 'example.Order' (Order.java:15) advised by before advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:77) [with runtime test]
    [AppClassLoader@92e78c] weaveinfo Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.())' in Type 'example.Order' (Order.java:15) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:86) [with runtime test]
    [AppClassLoader@92e78c] weaveinfo Join point 'initialization(void example.Order.())' in Type 'example.Order' (Order.java:15) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (AbstractDependencyInjectionAspect.aj:86) [with runtime test]


  3. Marc,

    Just added http://jira.springframework.org/browse/SPR-4593 based on your description. I will look into it shortly. Meanwhile, please add any test cases that you may have.

    -Ramnivas


  4. I'm thinking about performance issues when injecting dependencies in each created domain object and how to avoid the repeated overhead.
    What about to create a "static" field and inject in only once? Maybe after class-load. Usually my domain objects do not get different classes injected. So the restriction that all instances in a JVM can have only the same dependecies injected is no issue for me.
    What do you think?

    Greetings, Robert


  5. I like your principle "Make simple things simple" and I tend to be tempted by Robert's proposition.

    In some rare case (let's say, in a servlet filter, or else) I need to access beans, and those bean are
    99% of the time "singleton" beans.

    The simplest scenario would be for me to define a static setter on my servlet filter and rely on the container to set it once for all…
    The configuration could as easy as:

    The static scope (that I just invented here ;-) ) would mean:
    – do not instanciate MyServletFilter, just set the static field using the static setter…

    Would this be unacceptable ?

    regards,

    Nicolas.


  6. The fundamental problem with using a static field is that it represents a shared state. This leads to a few problems:
    - replacing the injected object during runtime would be very difficult to coordinate considering in-flight usages. For example, consider changing dependency between two method calls representing a coordinated set of operation. Blocking for all objects of a class to finish their in-flight operations may end up blocking the application for unduly longer duration. With the non-static injection, you have a choice to blocking the setter until the current in-flight operation for the injected object completes.
    - overriding dependency in subclass will be impossible. With instance-based DI, you can have different objects injected based on the concrete type of the domain object.

    For unit testing, using static fields introduce additional issues:
    - you must ensure that there are no leftover static fields from one test of another. With the DI approach suggested in the blog, each test creates a fresh test object and injects with fresh dependencies (say, mock objects). This avoids any inter-test conflicts.
    - you will have to forgo running multiple tests in parallel as mock or stub objects set as dependency in one test will interfere with other tests.

    So overall, the static field approach can work, but there are caveats to understand and accept.


  7. Hi Ramnivas,

    @Configurable-based approach is a very powerful feature. But the implementation has its weak points.
    Please read my old post on the topic:
    http://subject-ivity.blogspot.com/2007/09/injecting-dependencies-into-domain.html

    Regards,
    Uladzimir.


  8. Hi Ramnivas,

    I have tried to set up your @Configurable approach using gmail implementing mailSender and messageTemplate yet I'm out of luck, I've been trying a number of methods but
    when I call the class nothing is injected.

    I also went back to the XML approach yet it still won't work.
    The fourm explains all

    If you could give me some feedback it would be appericated

    http://forum.springsource.org/showthread.php?t=68558

    Regards,
    Allan


  9. Hi Ram,
    I would like to use spring to inject dependencies into my domain model. But, its not possible to do compile time dependency injection, because based on runtime data, i need to inject a particular type. For example, i have a wheelbase and the wheelbase references Tire. i have specific implementations of tire such as, jeep tire and truck tire. Hence, based on runtime data, i would like to either inject jeep tire or a truck tire into a wheel base. I was wondering if you have any aspects for springframework which could utilize spring to inject correct type of tire into a wheelbase based on runtime data inspection.


  10. The above concept is very useful and it is more programmatic and very useful.Programming concepts are very good. very great procedure…
    ————-
    Stevehalen


  11. The above concept is very useful and it is more programmatic and very useful.Programming concepts are very good. very great procedure…
    concept is superb..
    ————–
    Steve
    DNS Lookup

5 trackbacks

Leave a Reply