Скачать книгу

on the container API. Code can be moved from one container to another, and it should still work without any modification in the codebase. There is no requirement to implement any special interfaces at all. Written classes are just plain Java objects, and it is not necessary to deploy those components to make them run.

      Two dependency injection methods can be used. One is constructor injection, and the other is setter injection. A good container should be able to support both at the same time, and should allow mixing them.

      Setter Injection

      The setter methods are invoked immediately after the object is instantiated by the container. The injection occurs during the component creation or initialization phase, which is performed much earlier in the process than handling business method calls. Thus, there are no threading issues related with calling those setter methods. Setter methods are part of the JavaBean specification, so that they allow the outside world to change collaborators and property values of components. Those JavaBean properties are also used to externalize simple properties such as int or boolean values. This simplifies the code and makes it reusable in a variety of environments.

      The most important advantage of setter injection is that it allows re-configurability of the component after its creation. The component's dependencies can be changed at run time. Many existing classes can already be used with standard JavaBean-style programming. In other words, they offer getter and setter methods to access their properties. For example, Jakarta Commons DBCP DataSource provides a commonly used DataSource implementation, and it can be managed via its JavaBean properties within the container. It's possible to use the standard JavaBeans property-editor mechanism for type conversions whenever necessary. For example, a String value given in configuration can easily be converted into a necessary typed value, or a location can be resolved into a resource instance, and so on. If there is a corresponding getter for each setter, it becomes possible to obtain the current state of the component and save it to restore for a later time. If the component has default values for some or all of its properties, it can be configured more easily using setter injection. You can still optionally provide some dependencies of it as well.

      The biggest disadvantage of setter injection is that not all necessary dependencies may be injected before use, which leaves the component in a partially configured state. In some cases, the order of invocation of setter methods might be important, and this is not expressed in the component's contract. Containers provide mechanisms to detect and prevent such inconsistencies in component states during their creation phase.

      Constructor Injection

      With constructor injection, beans express their dependencies via constructor arguments. In this method, dependencies are injected during component creation. The same thread safety applies for constructor injection as well. You can also inject simple properties such as int or boolean values as constructor arguments.

      The biggest advantage of constructor injection is that each managed component in the container is guaranteed to be in a consistent state and ready to use after it is created. Another good point is that the amount of code written with constructor injection will be slightly less compared to the code written when setter injection is used.

      The biggest disadvantage of constructor injection is that it won't be possible to reconfigure components after their creation unless they provide a setter for those properties given as constructor arguments. Having several overloaded constructors for different configuration options might be confusing or even unavailable most of the time. Concrete inheritance can also be problematic unless you are careful about overriding all of the constructors in the superclass.

      Setter or Constructor Injection

      Both methods have advantages as well as disadvantages, and it is not possible to use only one method for any application. You might have classes especially written by third parties that don't have constructors that accept suitable arguments for your configuration case. Therefore, you might first create a component with an available constructor that accepts arguments close to your needs, and then inject other dependencies with setter methods. If the components need to be reconfigurable at run time, having setters for their specific properties will be mandatory in that case. IoC containers are expected to allow developers to mix the two types of dependency injection methods for the same component within the application configuration.

      SUMMARY

      In this chapter, you first learned the problems of the old-school EJB programming model that caused many enterprise Java projects to fail completely – or at least fail to satisfy their promises to some degree. The main problems of the old EJB programming model was that developers had to write several interfaces to create a business component, tight coupling between EJB and J2EE technologies was necessary, you couldn't run components outside the J2EE platform, there was difficulty in unit testing outside the container, long and complex develop-package-deploy-test cycles were required, and the characteristics and limitations of J2EE technologies required promotion of the procedural style of programming. Then you found out how those problems led to the creation of the POJO programming model, how the POJO programming model solves the problems of the EJB programming model, and how the POJO programming model helped J2EE to evolve into the new Java EE environment.

      This chapter discussed why so many people insisted on using J2EE technologies and tried to deploy their enterprise applications despite all those obstacles in the J2EE environment. After identifying the attractive points of the J2EE platform, we defined what a container is, listed fundamental features a container should offer to its applications, and identified what makes a container lightweight by looking at its characteristics.

      The last part of the chapter focused on what IoC is, and what any container should offer as its core services. We discussed how IoC helps make applications more modular and pluggable. The chapter wrapped up with an explanation of dependency injection, which is a form of IoC, and its two different types: setter injection and constructor injection.

      EXERCISES

      You can find possible solutions to the following exercises in Appendix A.

      1. Investigate the in-container test frameworks available today. What are their biggest advantages and disadvantages compared to testing outside the container?

      2. What IoC method is used by the new EJB programming model today?

      3. Which dependency injection method can handle “circular dependencies” and which cannot?

      ▶ WHAT YOU LEARNED IN THIS CHAPTER

      2

      Dependency Injection with Spring

WHAT YOU WILL LEARN IN THIS CHAPTER:

      • Configuring and using Spring Container

      • Using different types of configuration metadata to configure Spring Container

      • Understanding dependency resolution

      • Learning the advantages and disadvantages of autowiring

      • Performing explicit bean lookups in Spring Container

      • Learning different bean instantiation methods

      • Understanding scoped beans and available scopes

      • Learning how lazy bean creation works

      • Understanding life-cycle callbacks

      • Using bean definition profiles to create conditional bean configurations

      CODE DOWNLOAD The wrox.com code downloads for this chapter are found at www.wrox.com/go/beginningspring on the Download Code tab. The code is in the Chapter 2 download and individually named according to the names throughout the chapter.

      This chapter explains how you can apply dependency injection using the Spring Application Framework. You first look at different formats of configuration metadata necessary for the Spring Container to create and wire up objects in the system. The chapter includes examples for XML-, annotation-based, and Java-based configuration metadata formats.

Скачать книгу