Chapters 1 and 2 introduce the Spring framework, emphasizing its role in simplifying dependency injection (DI) through the principle of inversion of control (IoC), where components rely on an external service to provide their dependencies. This design pattern allows for a cleaner separation of concerns. The chapter outlines various IoC concepts, differentiating between dependency injection and dependency lookup, and discusses their respective advantages and disadvantages.

Key features covered include:

  • IoC Concepts: An overview of different IoC types, including their pros and cons.

  • IoC in Spring: An explanation of Spring’s IoC capabilities and the types of dependency injection it supports, such as setter, constructor, and method injection.

  • Spring’s DI Implementation: A focus on the IoC container, particularly the BeanFactory and the more advanced ApplicationContext, which offers enhanced functionalities.

  • Configuring Spring Context: Guidance on using annotations for configuring the ApplicationContext, with a preview of Groovy and Java configurations to be explored in Chapter 4. The discussion includes DI configuration and additional services from BeanFactory, like bean inheritance and lifecycle management.

Inversion of Control and Dependency Injection

Types of Inversion of Control

The content discusses the two types of Inversion of Control (IoC) in software development: Dependency Lookup and Dependency Injection, along with their respective implementations.

  1. Dependency Lookup: This traditional approach allows components to acquire dependencies from a registry. It includes:

    • Dependency Pull: Components fetch dependencies as needed, familiar to Java developers (e.g., using JNDI in EJB).

    • Contextualized Dependency Lookup (CDL): Components request dependencies from the container managing them, typically via a defined interface.

  2. Dependency Injection: A more flexible approach where the IoC container automatically provides dependencies to components, enhancing usability. It includes:

    • Constructor Dependency Injection: Dependencies are injected through a constructor, making them required for the component’s instantiation.

The document provides code examples illustrating these concepts, particularly in the context of the Spring framework, highlighting how IoC mechanisms work in practice.



sequenceDiagram participant CDLDemo participant DefaultContainer participant StandardOutMessageRenderer participant HelloWorldMessageProvider CDLDemo->>DefaultContainer: new DefaultContainer() CDLDemo->>StandardOutMessageRenderer: new StandardOutMessageRenderer() CDLDemo->>StandardOutMessageRenderer: performLookup(container) StandardOutMessageRenderer->>DefaultContainer: getDependency("provider") DefaultContainer->>StandardOutMessageRenderer: return HelloWorldMessageProvider StandardOutMessageRenderer->>HelloWorldMessageProvider: new HelloWorldMessageProvider() CDLDemo->>StandardOutMessageRenderer: render() StandardOutMessageRenderer->>HelloWorldMessageProvider: getMessage() HelloWorldMessageProvider-->>StandardOutMessageRenderer: "Hello World!" StandardOutMessageRenderer->>CDLDemo: Output "Hello World!"

classDiagram %% Interfaces class Container { +Object getDependency(String key) } class ManagedComponent { +void performLookup(Container container) } class MessageProvider { +String getMessage() } class MessageRenderer { +void render() } %% Classes implementing interfaces Container <|.. DefaultContainer MessageProvider <|.. HelloWorldMessageProvider MessageRenderer <|.. StandardOutMessageRenderer MessageRenderer <|-- ManagedComponent %% Class Definitions class DefaultContainer { +Object getDependency(String key) } class HelloWorldMessageProvider { +String getMessage() } class StandardOutMessageRenderer { -MessageProvider messageProvider +void performLookup(Container container) +void render() } %% Relationships StandardOutMessageRenderer --> MessageProvider : uses StandardOutMessageRenderer ..> Container : performs lookup DefaultContainer o-- HelloWorldMessageProvider : creates CDLDemo --> DefaultContainer : uses CDLDemo --> StandardOutMessageRenderer : uses

Setter Dependency Injection

The text discusses setter dependency injection, a method where an IoC (Inversion of Control) container injects dependencies into a component using setter methods, exemplified by the StandardOutMessageRenderer. This approach allows for the creation of objects without their dependencies, which can be set later. Setter injection is favored for its simplicity and is the most commonly used method in IoC.

The document contrasts injection with lookup style IoC. While lookup requires explicit retrieval of dependencies from an IoC container (which can complicate testing), injection allows for easier testing and decouples components from the IoC container. It emphasizes that using injection simplifies code maintenance and reduces the likelihood of errors, as the dependencies are provided directly without additional retrieval logic.

Ultimately, the text advocates for the use of dependency injection over lookup due to its straightforwardness and ease of use, suggesting that it leads to cleaner, less error-prone code.

Setter Injection vs. Constructor Injection

The text discusses two primary methods of dependency injection: constructor injection and setter injection.

  • Constructor Injection: This method is preferred when a dependency is essential for a component’s functionality. It ensures that required dependencies are explicitly defined, promoting immutability (e.g., declaring fields as final). This approach is also container-agnostic, meaning it can be applied without being tied to a specific framework.

  • Setter Injection: This method allows for more flexibility, enabling components to expose their dependencies while providing default values. It can be beneficial for configuration parameters, which differ from typical dependencies in that they are passive, often simple values, and provide necessary information rather than being active components.

The text emphasizes the importance of distinguishing between configuration parameters and actual dependencies. Configuration parameters can be defined in business interfaces if they are applicable to all implementations. The example of a NewsletterSender interface illustrates this, where configuration parameters like SMTP server details are included.

Ultimately, the choice between constructor and setter injection should depend on the specific use case: constructor injection is best for enforcing essential dependencies and creating immutable objects, while setter injection is more flexible, allowing for dynamic dependency changes and default values.

Inversion of Control in Spring

The text discusses the concept of Inversion of Control (IoC) in the Spring framework, emphasizing the importance of dependency injection as its core implementation. It highlights that dependency injection is the preferred method for connecting dependent objects and their collaborators, while dependency lookup is necessary in scenarios where automatic wiring is not possible, such as in standalone Java applications. In web applications using Spring MVC, Spring can automatically manage component connections. The document also mentions that Spring’s IoC container can adapt to external dependency lookup containers and supports both constructor and setter injection. The chapter will cover the fundamentals of Spring’s Dependency Injection (DI) container with numerous examples.

Dependency Injection in Spring

Beans and BeanFactory

The Spring Framework’s IoC (Inversion of Control) container is primarily built on the org.springframework.beans and org.springframework.context packages, with the BeanFactory interface at its core. This interface manages components, their dependencies, and life cycles, allowing for the creation and configuration of beans, which are objects managed by the IoC container. While beans typically follow the JavaBeans specification, this is not mandatory, especially with constructor injection.

Applications that require dependency injection (DI) can use the BeanFactory interface, which necessitates creating an instance of a class that implements it and configuring it with bean information. Although setups can often be automated (e.g., in web applications), manual configuration is common in examples.

The ApplicationContext interface extends BeanFactory, offering additional services such as integration with AOP, internationalization, event handling, and application-specific contexts. It is recommended to use ApplicationContext for developing Spring applications, which can be bootstrapped manually or via web containers using ContextLoaderListener. Subsequent examples in the material will focus on using ApplicationContext and its implementations.

Basic Configuration Overview

The content describes how to configure a stand-alone Spring application using a class annotated with @Configuration. This annotation signifies that the class contains methods marked with @Bean, which declare beans. This setup is useful for integrating third-party libraries since you can’t modify their code to declare beans. Additionally, the class can use @ComponentScan to automatically find existing bean declarations marked with annotations like @Component.

The Spring container processes these classes to generate bean definitions and manage their lifecycle, which includes creating objects, determining their creation order, and handling initialization and disposal. This collection of instructions is known as configuration metadata.

The document illustrates a simple Spring configuration class (HelloWorldConfiguration) with two beans (provider and renderer). The configuration is bootstrapped using AnnotationConfigApplicationContext, which creates a Spring application context. The example shows how to retrieve a bean using getBean and execute its method.

The process involves instantiating AnnotationConfigApplicationContext with the configuration class, creating a Spring IoC container that registers and manages the beans, and allowing beans to be accessed and utilized. This results in the "Hello World!" message being printed to the console.

Declaring Spring Components

The text provides a detailed overview of using stereotype annotations in Spring to define beans directly within classes. These annotations, part of the org.springframework.stereotype package, help specify the role of different beans in an application. Key stereotype annotations include @Service, @Repository, and @Component, with @Component serving as a meta-annotation for auto-detection in annotation-based configurations. Beans can be defined by annotating classes with these stereotypes and using @Autowired for dependency injection.

The document includes examples of how to declare beans using these annotations, and how to configure Spring’s ApplicationContext using @ComponentScan for automatic component scanning. This scanning can be customized using attributes like basePackages, basePackageClasses, includeFilters, and excludeFilters to control which packages or classes are scanned for bean definitions.

Additionally, the text notes that Spring supports mixing XML and Java configuration, allowing for flexible and creative bean definition strategies, which will be further elaborated in a subsequent chapter.