Saturday, January 30, 2010

Spring: @Autowired Constructors

Since the introduction of Spring 2.0, I have seen a trend where developers use the @Autowired annotation very often. I must admit, I like a combination of annotations with some XML declaration, however I'm still debating whether making a decision of using @Autowired scales well in the long run. I would like to show how this feature can seem unintuitive.  Furthermore, even tools like SpringSource Tool Suite can get confused at times.

Consider the following two POJOs:
public class FirstPojo implements Pojo {
  /**
   * Default constructor, no argument
   */
  public FirstPojo() {
  }
  // Other methods and logic here
}

public class SecondPojo implements Pojo {
  /**
   * Default constructor, with one argument
   */
  @Autowired
  public SecondPojo(Pojo firstPojo) {
  }
  // Other methods and logic here
}
Notice that one contains a constructor which is annotated with @Autowired. What this means is that you can potentially have the container define such a bean as follows:

Can you see the problem there? Now our declared XML claims that the SecondPojo has a constructor with no parameters, even though we can clearly see that such is not the case. It's hard to explain the average user that such behavior is possible due to Spring-AOP and how these kind of beans are really proxy objects.  When the container detects an @Autowired constructor, the Spring-AOP infrastructure ensures that such constructor exists (so as to execute whatever logic is within that constructor). Also note that all dependencies are also @Required (as per the docs).  Furthermore, it looks like the SpringSource Tool Suite (as of the writing of this entry) also has problems detecting this "feature" as normal behavior.  See JIRA issue IDE-1042 for more information (looks like it's planned to be fixed on the soon to be 2.3.1 release).

Now, my personal feeling is that this @Autowired behavior is due to the mixing of declarative XML with annotations. Not necessarily a bad design from SpringSource, but simply a consequence of Spring's goal of helping with simplicity. @Autowired is really simple to use, but without full understanding of what's really happening, it can be confusing in the long term, particularly when a project grows in the number of managed beans. A good strategy (mostly maintained through the discipline of code reviews) is to choose this @Autowired constructors to also be detected with yet another annotation (e.g. @Component, @Service, @Repository, etc).  If a bean already has an @Autowired constructor, it only makes sense to continue annotating the class (at the class level of course) with one of these stereotypes annotations so as to make it very clear how this beans is to work and how it's dependencies be injected. Interestingly enough, SpringSource Tool Suite seems to like this approach and can even graph it nicely.

No comments: