Spring Dependency Injection

One of the core features of Spring is to perform “dependency injection”. This creates relationships between complex Spring components and lets the linking of these components be handled by the Spring configuration instead of by a custom framework or “factory pattern” developed as part of the application.

In this lab you will see several ways to configure this dependency injection. You will also see various options for “auto-wiring” which is the automatic dependency injection of Spring.

1. Lab Setup

  1. Import the projects in the ‘<LABFILES>Spring‑DI‑XMLSpring‑DI‑XML‑Starter.zip‘ file as described in the ‘Common Lab Preparation Steps’ at the ‘Lab Setup’ part.

  2. Open the Spring perspective.
  3. In the Markers view check that you have only warnings and no errors from the project. If there are errors try a Project → Clean to rebuild the project.

Inject Spring Bean

The first step to using dependency injection is to inject one Spring bean into another. The Java classes imported already have this relationship and you will use Spring to initialize this dependency.

  1. Open BasicProductCodeGenerator.java under Spring‑DI‑XML → src → com.webage.bean package.Notice the following field ‘intGenerator’ in the class.private IntGenerator intGenerator;IntGenerator is an interface that lets this Spring component obtain the “next” int value to assist in generating product codes. Also notice there is a ‘setIntGenerator’ method as well as several constructors, one of which takes a String prefix and an IntGenerator instance.
  2. Open IncrementingIntGenerator.java under Spring‑DI‑XML → src → com.webage.bean package.This is just a simple implementation of the IntGenerator interface which has properties for the starting value and increment amount that will be used to provide the next ‘int’ value.
  3. Open spring-beans.xml under the Spring‑DI‑XML → src folder.
  4. Click the ‘Source‘ tab at the bottom of the editor.
  5. In the ‘prodCodeGenerator’ bean definition, find the comment about injecting an ‘intGenerator’ and add the following <constructor-arg> and nested <bean> elements shown in bold. Check the syntax of the XML elements carefully to make sure tags are balanced and valid XML.<bean id=”prodCodeGenerator”scope=”prototype”><constructor-arg><value>INT</value></constructor-arg><!– Need injection of ‘intGenerator’ –><constructor-arg><bean></bean></constructor-arg></bean>
  6. Save the spring-beans.xml file. At this point there should be no errors in the project. Check the Markers view if errors are shown.
  7. Open ProductCodeGeneratorTest.java under Spring‑Beans → src → com.webage.test package. Notice this class simply loads the ‘spring-beans.xml’ bean configuration, retrieves the ‘prodCodeGenerator’ bean and prints out a few product codes. Notice the bean is retrieved twice which will be important for bean scope.
  8. With the ProductCodeGeneratorTest class still open in the editor select Run → Run As → AspectJ/Java Application from the Eclipse menus.

    Note: If you get an error when trying to run the code it is likely because you selected Run As → Java Application which does not seem to work. This option does not seem to add the project code to the classpath and therefore can’t run the application.If this happens it is best to select Run → RunConfigurations so you can delete the incorrect run configuration so it won’t cause problems in the future.

  9. Make sure that you get the following in the Console view when the class generates some basic product codes. Notice that the int values used to generate the codes restarts with the second set of codes.

    Note: The product codes restart with the second set because the bean definition for the ‘prodCodeGenerator’ bean is prototype scope and is recreated each time the bean is retrieved from the Spring container. Because the nested <bean> element for the IntGenerator dependency is a “private” or “inner” bean the effect is that it is also at prototype scope even though this is not specified in the <bean> element.

  10. Return to the editor for the ‘spring-beans.xml’ file.
  11. Modify the <constructor-arg> elements into <property> elements as shown below using the given property names. Make sure to modify the end tag for the element also.<bean id=”prodCodeGenerator”scope=”prototype”><property name=”prefix”><value>INT</value></property><!– Need injection of ‘intGenerator’ –><property name=”intGenerator”><bean></bean></property></bean>
  12. Save the file and make sure there are no errors. These will occur if the XML elements were not modified correctly.
  13. From the menus select Run → Run History → ProductCodeGeneratorTest. There may be other things listed but this should be the only entry with that name.
  14. Check that the output in the Console view is the same as last time. Although you are doing “setter” injection with the properties instead of “constructor” injection the behavior is the same.


    Note:
    It is important that the BasicProductCodeGenerator class had a “no-argument” constructor in addition to the constructor that took a prefix and IntGenerator. If there were not a “no-argument” constructor, Spring would not have been able to create the bean instance with no constructor arguments listed in the Spring configuration and would have thrown a BeanCreationException.

  15. Return to the editor for the ‘spring-beans.xml’ file.
  16. Modify the syntax of the ‘intGenerator’ property element so that instead of a nested <bean> element it uses a nested <ref> element as shown in bold below. This will reference another bean definition for an IncrementingIntGenerator bean already present in the Spring configuration.<bean id=”prodCodeGenerator”scope=”prototype”>…<!– Need injection of ‘intGenerator’ –><property name=”intGenerator”><ref bean=”intGenerator”/></property></bean>
  17. Save the file and make sure there are no errors. These will occur if the XML elements were not modified correctly.
  18. From the menus select Run → Run History → ProductCodeGeneratorTest.
  19. Notice that the output in the Console view shows six product codes that start at ’25’ and increment by ‘5’ because of the properties set for the referenced bean definition. Notice however that this time the int values do not reset with the second set of three product codes.

    Note: This behavior is because the separate ‘intGenerator’ bean definition was not an “inner” or “private” bean definition. Therefore it picks up the default value of ‘singleton’ for the bean scope. This means that even though there are two BasicProductCodeGenerator instances being retrieved from the Spring container they appear to be only one instance because the IntGenerator injected into both of them is a singleton and does not get recreated.

  20. Return to the editor for the ‘spring-beans.xml’ file.
  21. Modify the definition of the ‘intGenerator’ bean so it is using the ‘prototype’ scope as shown in bold below.<bean id=”intGenerator”scope=”prototype”>
  22. Save the file and make sure there are no errors.
  23. From the menus select Run → Run History → ProductCodeGeneratorTest.
  24. Notice in the Console view that this time the second set of product codes does start over at ’25’. This is because the IncrementingIntGenerator instance is getting recreated when it is injected into the second instance of the BasicProductCodeGenerator instance.

    Note: This behavior is only because both beans are at ‘prototype’ scope. If the BasicProductCodeGenerator bean was singleton scope, it would have only been created once and you would see the int values not
    resetting no matter what the scope of the IncrementingIntGenerator bean. Injection is only performed when an instance of the bean is created.

Inject Collection

Another “complex” thing that can be injected is a collection of other things. These can be injected into properties that are array or Collection types like List, Set, etc. Although there are very many different ways that this could be used, this lab will show injecting a List of values for a property on the BasicProductCodeGenerator bean.

  1. Open BasicProductCodeGenerator.java under Spring‑DI‑XML → src → com.webage.bean package.Notice the following fields in the class for a ‘suffixList’ and ‘suffixIterator’. These are used to contain a list of suffixes to be used with product codes and a way to iterate over that list so that each time a product code is generated it uses the next suffix from the list.@SuppressWarnings(“rawtypes”)private List suffixList = null;@SuppressWarnings(“rawtypes”)private Iterator suffixIterator;Note: You can ignore the @SuppressWarnings annotations. They are
    just there to avoid getting warnings since these fields do not use
    Generics until later.
  2. Examine the ‘setSuffixList’ and ‘getNextProductCode’ methods to understand more about how the suffixes are used.
  3. Return to the editor for the ‘spring-beans.xml’ file.
  4. Add a new nested <property> element to the ‘prodCodeGenerator’ bean definition with an embedded <list> as shown in bold below. Make sure you nest the new element correctly as the code below does not show the other two properties to simplify things.<bean id=”prodCodeGenerator” …>…<property name=”suffixList”><list><value>50</value><value>60</value></list></property></bean>
  5. Save the file and make sure there are no errors. These will occur if the XML elements were not added correctly.
  6. From the menus select Run → Run History → ProductCodeGeneratorTest.
  7. Notice from the Console view that you now have suffixes of ’50’ or ’60’ printed at the end of each product code. The suffixes restart after the end of the list is reached which is the behavior coded into the component. The suffixes also restart for the second generator because of the bean scope behavior.

  8. Return to the BasicProductCodeGenerator editor and reopen it if you closed it.
  9. Find the ‘getNextProductCode’ method and make the changes shown in bold below. You will have an error until the next step. There are only two lines of modified code but the entire method is shown to make sure you place the modified code in the correct location.public String getNextProductCode() {String toReturn = prefix + intGenerator.nextNumber();if (suffixIterator != null) {// suffixIterator won’t exist if there// is no list of suffixesif (!suffixIterator.hasNext()) {// Start at the beginning of// suffix list with new iteratorsuffixIterator =this.suffixList.iterator();}DecimalFormat format = new DecimalFormat(“0000”);toReturn += format.format(suffixIterator.next());}return toReturn;}

    Note: Since our <list> element in the bean definition appears to use integer values this code should be able to format those numbers for us.

  10. Organize imports by selecting Source → Organize Imports.
  11. Save the file and make sure there are no errors.
  12. From the menus select Run → Run History → ProductCodeGeneratorTest.
  13. Notice in the Console view you get an Exception. The exception indicates the given object can’t be formatted as a number.

    Note: This occurs because by default Spring will treat all values as Strings. This means the List that Spring created was a List of Strings with the Strings “50” and “60”. This causes errors in the format code.

  14. Return to the editor for the ‘spring-beans.xml’ file.
  15. Modify the definition of the <list> used for the ‘suffixList’ property to include the ‘value-type‘ attribute as shown in bold below.<property name=”suffixList”><list value-type=”int”><value>50</value><value>60</value></list></property>
  16. Save the file and make sure there are no errors.
  17. From the menus select Run → Run History → ProductCodeGeneratorTest.
  18. Notice in the Console view that this time there is no Exception and the product codes are generated as before.

  19. Return to the BasicProductCodeGenerator editor and reopen it if you closed it.
  20. Modify the declaration of the ‘suffixList‘ and ‘suffixIterator‘ fields to include the generic qualifier <Integer> as shown in bold below. You can also remove the @SuppressWarnings annotations if you want.private List<Integer> suffixList = null;private Iterator<Integer> suffixIterator;
  21. Modify the declaration of the parameter for the ‘setSuffixList‘ method to include the generic qualifier <Integer> as shown in bold below. You can also remove the @SuppressWarnings annotations if you want.public void setSuffixList(List<Integer> suffix) {
  22. Save the file and make sure there are no errors.
  23. Return to the editor for the ‘spring-beans.xml’ file.
  24. Modify the definition of the <list> used for the ‘suffixList’ property to remove the ‘value-type‘ attribute. The syntax is now back to what it was before without any type information needed in the Spring configuration file.<property name=”suffixList”><list><value>50</value><value>60</value></list></property>
  25. Save the file and make sure there are no errors.
  26. From the menus select Run → Run History → ProductCodeGeneratorTest.
  27. Notice in the Console view you did not get any errors and the product codes are generated. This is because Spring can use the generic type qualifiers in the field and method to determine the type of the <list> elements and use Integer values that will not have any problem with the formatting code.

    Note: Since Spring 3.0 requires Java SE 5 or better, generics will always be supported in a Spring 3.0 application. It is suggested that you use generics as shown in this last example because the Java code you
    write will be much more type-safe and the Spring configuration can infer the type of collection elements from the generic.

  28. Return to the editor for the ‘spring-beans.xml’ file.
  29. Click the ‘Namespaces‘ tab at the bottom of the editor.
  30. Check the ‘util‘ namespace as shown below and click the OK button on the dialog that appears when you do.

  31. Click the ‘Source‘ tab at the bottom of the editor.
  32. Add the following <util:list> definition to the end of the configuration file but within the ending </beans> tag as shown below….</bean><util:list id=”suffixList”list-><value>230</value><value>220</value></util:list></beans>Note: You could also use the ‘util‘ tab of the editor to build up this definition. We are using the ‘Source‘ tab for simplicity.
  33. Modify the ‘suffixList‘ property of the ‘prodCodeGenerator‘ bean so that instead of defining an embedded <list> it uses a <ref> element to reference the <util:list> definition you just created.<property name=”suffixList”><ref bean=”suffixList”/></property></bean>
  34. Save the file and make sure there are no errors.
  35. From the menus select Run → Run History → ProductCodeGeneratorTest.
  36. Notice in the Console view that the suffixes of the output product codes are now different because the values of the separately defined <util:list> were different. All of the other behavior is the same.

    Note: Although not really apparent in this example, one of the benefits of the <util:list> syntax is the ability to define what implementation class should be used for the collection. This could give performance benefits for large collections.

It is also easy to define reusable collections of properties or values that can then be injected into multiple Spring beans.

Autowire Dependencies

The configuration of Spring bean dependencies is often called “wiring”. Spring also has a capability to “autowire” these dependencies. There are several different ways this can be done and this section will
demonstrate them.

  1. Return to the editor for the ‘spring-beans.xml’ file. Open it again if you had closed it.
  2. Modify the declaration of the ‘prodCodeGenerator‘ bean to add the ‘autowire’ attribute with the setting to autowire ‘byName‘ as shown in bold below.<bean id=”prodCodeGenerator”scope=”prototype” autowire=”byName”>
  3. Comment out the definition of the wiring of the ‘intGenerator‘ and ‘suffixList‘ properties as shown below. Note that when you add a starting comment tag Eclipse will automatically add the ending tag which you will have to delete and add further down.<!– Need injection of ‘intGenerator’ –><!–<property name=”intGenerator”><ref bean=”intGenerator” /></property><property name=”suffixList”><ref bean=”suffixList”/></property>–></bean>
  4. Save the file and make sure there are no errors. These will occur if the XML comment tags were not added correctly.
  5. From the menus select Run → Run History → ProductCodeGeneratorTest.
  6. Notice in the Console view that the output should be the same. This is because the autowiring by name is resolving the same dependencies to inject as were present before.

  7. Return to the editor for the ‘spring-beans.xml’ file.
  8. Modify the type of autowiring of the ‘prodCodeGenerator‘ bean to ‘constructor‘ as shown below.<bean id=”prodCodeGenerator”scope=”prototype” autowire=”constructor“>
  9. Save the file and make sure there are no errors.
  10. From the menus select Run → Run History → ProductCodeGeneratorTest.
  11. Notice in the Console view that the output is different. This is because even though there is a constructor with List<Integer> and IntGenerator arguments the standalone list can’t be autowired this way. It can only be autowired by name. So the constructor with only the IntGenerator is picked and no suffix list is used.

  12. Return to the editor for the ‘spring-beans.xml’ file.
  13. Modify the type of autowiring of the ‘prodCodeGenerator‘ bean to ‘byType‘ as shown below.<bean id=”prodCodeGenerator”scope=”prototype” autowire=”byType“>
  14. Save the file and make sure there are no errors.
  15. From the menus select Run → Run History → ProductCodeGeneratorTest.
  16. Notice in the Console view that the output is the same as the autowiring by constructor. Again the suffix list can’t be autowired by type.

    Note: It is possible to autowire an array or collection multi-value property by type or constructor. This can only be done though to collect all of the separately defined Spring beans of that type into the
    array or collection. The ‘suffixList’ <util:list> definition doesn’t work because it is a single bean defined as the entire list already.

  17. Return to the editor for the ‘spring-beans.xml’ file.
  18. Add the following new <bean> definitions to the end of the configuration file but before the end </beans> tag.</util:list><bean ><constructor-arg value=”110″></constructor-arg></bean><bean ><constructor-arg value=”120″></constructor-arg></bean></beans>
  19. Save the file and make sure there are no errors.
  20. From the menus select Run → Run History → ProductCodeGeneratorTest.
  21. Notice in the Console view that the output is back to containing suffix values but the suffix values are the ones coming from the separately defined beans of the Integer class.

Resolve Ambiguity of byType Autowiring

When autowiring by type (and also using the constructor method) there can be uncertainty of which Spring bean to use if more than one for a type exist. There are various ways to resolve this issue. In this section you will introduce this kind of problem and then resolve it using a few different means.

  1. Return to the editor for the ‘spring-beans.xml’ file.
  2. Check that the ‘prodCodeGenerator’ bean is set to autowire ‘byType’ as shown below.<bean id=”prodCodeGenerator”scope=”prototype” autowire=”byType“>
  3. Add the following new <bean> definition to the end of the configuration file but before the end </beans> tag.</bean><bean id=”randomGenerator”></bean></beans>
  4. Save the file and make sure there are no errors.
  5. From the menus select Run → Run History → ProductCodeGeneratorTest.
  6. Notice in the Console view that there is an ‘UnsatisfiedDependencyException’ thrown. If you look closely at the messages you should see that it is because there is “no unique bean” for the ‘intGenerator’ property. This is because the bean above you defined is also an implementation of the IntGenerator interface.
  7. Return to the editor for the ‘spring-beans.xml’ file.
  8. Find the definition of the ‘intGenerator‘ bean and add the ‘autowire-candidate‘ attribute with a value of ‘false’ as shown below.<bean id=”intGenerator”scope=”prototype” autowire-candidate=”false”>
  9. Save the file and make sure there are no errors.
  10. From the menus select Run → Run History → ProductCodeGeneratorTest.
  11. Notice in the Console view that you get product codes generated with the random numbers from the second component (which are longer). There is no more error because the IncrementingIntGenerator bean is excluded from autowiring.

  12. Return to the editor for the ‘spring-beans.xml’ file.
  13. Find the definition of the ‘intGenerator‘ bean. Remove the ‘autowire‑candidate‘ attribute and add a ‘primary‘ attribute with a value of “true”. Both changes are shown below in bold with the attribute to be removed shown with a strikethrough effect.<bean id=”intGenerator”scope=”prototype” primary=”true” autowire-candidate=”false”>
  14. Save the file and make sure there are no errors.
  15. From the menus select Run → Run History → ProductCodeGeneratorTest.
  16. Notice in the Console view that the output has returned to using the incrementing product codes and you also still do not get an error. Although both beans are again eligible for auto-wiring, Spring now knows which one to prefer.

    Note: Both of these techniques can be used to establish perhaps a default bean for autowiring and leave other bean definitions to be used with explicit wiring.

  17. Lab Cleanup

  18. Delete the ProductCodeGeneratorTest run configuration from the AspectJ/Java Application run configurations as described in the ‘Common Lab Preparation Steps’ at the ‘Lab Cleanup’ part.
  19. Close the Spring-DI‑XML project as described in the ‘Common Lab Preparation Steps’ at the ‘Lab Cleanup’ part.

    Review

There are several ways to inject dependencies into Spring components. In this lab you saw some of the major choices. This includes autowiring where Spring determines which bean should be injected. You also saw that some types of autowiring may have uncertainty for which bean to inject and how to resolve this issue to behave the way that might make sense for the application.