Rich Newman

May 10, 2010

A Comparison of Some Dependency Injection Frameworks: Part 3 Spring with XML Configuration (Java)

Introduction

Part  2 of this series of articles discussed some tests we will be applying to a variety of dependency injection frameworks.  It also showed the classes that didn’t substantially change regardless of the framework.

This article will look at how we run these tests in the Spring framework.

Code

The full code for the examples in this article is available.  This download is an Eclipse project, and contains all required dependencies.  All you should need to do is to import the the downloaded zip file into Eclipse and the code should run successfully.  To do this I’m using Eclipse Galileo, which is the latest version at the time of writing.  Here the menu options are File/Import…/ Existing Projects into Workspace (under General)/select the downloaded zip file.

Testing Spring with XML Configuration

The XML configuration for our Spring project is straightforward, as is the associated client startup class that uses it.  In the sections below we look in a little more detail at how we do the configuration and retrieve and use our objects using Spring.

Test 1: Configuration and retrieval of an object with (only) string dependencies 

As discussed in part 2, we use the Movie class to run this test.  The XML configuration for this is below: we tell spring we need a bean with an id of ‘AndreiRublevMovie’ instantiated from class Movie, and we pass in string values for the two constructor arguments:

      <bean id="AndreiRublevMovie" class="moviefindertest.springxml.Movie">
            <constructor-arg name="title" value="Andrei Rublev"></constructor-arg>
            <constructor-arg name="director" value="Andrei Tarkovsky"></constructor-arg>
      </bean>

We can then retrieve an object configured as above from our container with the code below:

            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            Movie andreiRublev = (Movie) context.getBean("AndreiRublevMovie"); 

Obviously this isn’t a very useful test on its own, but it does show that in Spring configuring an object with constructor injection is fairly easy and intuitive.

Test 2:  Injection of an object into an instance of a class.

Similarly our second test is to inject a (singleton) instance of SimpleMovieFinder into an instance of our MovieLister class using constructor injection.  The configuration for this is as below:

      <bean id="simpleMovieFinder" class="moviefindertest.springxml.SimpleMovieFinder"></bean>
      <bean id="simpleMovieLister" class="moviefindertest.springxml.MovieLister" scope="singleton">
            <constructor-arg name="finder" ref="simpleMovieFinder"></constructor-arg>
      </bean>

SimpleMovieFinder gives MovieLister a hard-coded list of movies, including several James Cameron movies.  In the startup class we  retrieve the instance of MovieLister from the container as you would expect, and then use the moviesDirectedBy method to retrieve the James Cameron movies:

            MovieLister simpleLister = (MovieLister) context.getBean("simpleMovieLister");
            Movie[] jamesCameronMovies = simpleLister.moviesDirectedBy("James Cameron");
            for(Movie movie : jamesCameronMovies){
                  System.out.println(movie.toString());
            }

This is a more useful test than 1. above since we’re actually configuring our object.  Again the syntax for injecting one object into another is simple with Spring, and again retrieving the object and using it is easy.

Test 3:  Injection of a different object into an instance of the same class as used in test 2.

The third test is to inject a different object (an instance of ColonDelimitedMovieLister)  into an instance of the same class as in the test above (MovieLister). 

      <bean id="colonDelimitedMovieFinder" class="moviefindertest.springxml.ColonDelimitedMovieFinder"></bean>
      <bean id="colonDelimitedMovieLister" class="moviefindertest.springxml.MovieLister" scope="prototype">
            <property name="finder" ref="colonDelimitedMovieFinder"></property>
      </bean>

            MovieLister colonDelimitedLister = (MovieLister) context.getBean("colonDelimitedMovieLister");
            Movie[] martinScorseseMovies = colonDelimitedLister.moviesDirectedBy("Martin Scorsese");
            for(Movie movie : martinScorseseMovies){
                  System.out.println(movie.toString());
            } 

As we shall see, in several other DI frameworks doing this isn’t particularly easy.  Here the XML and code are almost identical to the code for the second test above.  Note that it’s a different list of movies (retrieved from a text file), and a different director.  Note also that we configure the MovieLister with scope=”prototype”:

Tests 4 and 5:  Creation of an object with singleton scope, creation of an object with prototype scope

For these tests we re-use the configuration in tests 3 and 4 above.  In test 3 simpleMovieLister was configured with singleton scope.  This means if we use getBean to retieve simpleMovieLister a second time it should return the same object.  In test 4 colonDelimitedMovieLister was configured with prototype scope.  This means a second request should return a new object.

Some simple version numbers in the MovieLister class itself let us identify whether we have the same or a different object when the tests are run.

Tests 6 and 7:  Factory Method and Injection of the Container

Part 2 of this series of articles showed the code that was invariant across all of the frameworks tested here, and briefly discussed our final two tests.  These involve:

  • Creating a MovieFinder class using a factory class and method.
  • Injecting the container itself into that factory class so that all objects of type Movie could be retrieved from it.

The factory class itself inevitably varies depending on which framework you are using.  The code for this factory class with Spring is available.  In Spring we implement the BeanFactoryAware interface, which has a setBeanFactory method, to inject the container into a class.  The ‘bean factory’ is the container, and as shown this has methods like getBeansOfType which allow us to get all objects of a certain type configured in the container.  This is pretty straightforward.

Now we can configure our MovieLister, which is simply returned from the ‘build’ method on the factory class.  Setting this up in Spring XML is again straightforward: we simply set the factory-bean attribute of our bean configuration to be the id of an instance of the factory class, and the ‘factory-method’ attribute to be the name of the method:  

      <bean id="complexMovieListerBuilder" class="moviefindertest.springxml.ComplexMovieListerFactory"></bean>
      <bean id="complexMovieLister" factory-bean="complexMovieListerBuilder" factory-method="build" scope="prototype"></bean>

 Now we can use the bean in exactly the same way as in our other tests: it doesn’t matter that the bean configuration is calling a method to construct the object, rather than just instantiating a class (as in our other tests):

            MovieLister complexLister = (MovieLister) context.getBean("complexMovieLister");
            Movie[] tarkovskyMovies = complexLister.moviesDirectedBy("Andrei Tarkovsky");
            for(Movie movie : tarkovskyMovies){
                  System.out.println(movie.toString());

Comments on Spring

Spring has, of course, been a very successful framework, and part of that is the simplicity of the dependency injection configuration.  It’s easy to set up the XML configuration, and it’s fairly easy to understand what it’s doing by just looking at it.  The syntax is certainly less obscure than some of the other frameworks we will be looking at in this series of articles.  It’s not Java, of course, so  the developer is still having to learn a new way of instantiating their objects from what they were taught in Java 1.01. 

Spring configuration is almost totally non-intrusive.  That is, if you are using dependency injection to inject an instance of one class into an instance of another class then you don’t have to change the code of either class at all.  All the work can be done in the XML and the configuration of the container.

Spring is also quiet powerful.  It can run all of our tests successfully.   Having said that, the tests are pretty arbitrary.  The framework I’m most familiar with is Spring, so that tests may be tailored to what Spring can do, particularly tests 6 and 7.

So Spring is, as we know, a pretty good dependency injection framework.  However, as I discussed in part 1, XML configuration of the kind we use here has a number of drawbacks.  The most important of these to me is the fact that it can be difficult to maintain and debug XML configuration, particularly on large projects.

Later articles in this series will look at whether there are alternatives to Spring that address these drawbacks.

Conclusion

This article briefly examined using XML configuration in Spring for dependency injection in Java.  Part 4 of the series will even more briefly look at running the same tests in Spring.Net.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: