A study note based on Spring Framework Documentation. The current version is 5.3.0.

1 Overview

Spring has a core of Spring Framework and projects based on the core.

  • The core includes a configuration model and a DI mechanism.
  • Projects include messaging, transactional data and persistence, Servlet-based Spring MVC web framework and Spring WebFlux reactive web framework. Additional project include Spring Boot, Spring security, Spring Cloud, Spring Batch that are developed in separate repositories.

Spring was created in 2003 and embraces Java Servlet API, WebSocket API, concurrenty utilities, JSON binding API, Bean Validation, JPA, JMS and JTA.

2 The IoC Container

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory that adds event publication and application-layer specific context such as WebApplicationContext for use in web applications.

The ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML, Java annotations, or Java code.

Several implementations of the ApplicationContext interface are supplied with Spring. In most application scenarios, explicit user code is not required to instantiate one or more instances of a Spring IoC container. Your application classes are combined with configuration metadata so that, after the ApplicationContext is created and initialized, you have a fully configured and executable system or application.

3 Configuration Metadata

Configuration metadata can be

  • XML-based
  • Annotation-based: @Required, @Autowired, @Resource etc.
  • Java-based

Spring configuration consists of at least one and typically more than one bean definition that the container must manage. XML-based configuration metadata configures these beans as <bean/> elements inside a top-level <beans/> element. Java configuration typically uses @Bean annotated methods within a @Configuration class.

These bean definitions correspond to the actual objects that make up your application. Typically, you define service layer objects, data access objects (DAOs), presentation objects, infrastructure objects such as Hibernate sessions, JMS Queues, and so forth. Typically, one does not configure fine-grained domain objects in the container, because it is usually the responsibility of DAOs and business logic to create and load domain objects.

After you define the metadata, you can

  • Load Metadata: the location path or paths supplied to an ApplicationContext constructor are resource strings that let the container load configuration metadata from a variety of external resources, such as the local file system, the Java CLASSPATH, and so on.
  • Use the Container: the ApplicationContext is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. By using the method T getBean(String name, Class<T> requiredType), you can retrieve instances of your beans.

4 Bean

Within the IOC container itself, bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:

  • A package-qualified class name: typically, the actual implementation class of the bean being defined.
  • Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
  • References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
  • Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.

A bean definition is essentially a recipe for creating one or more objects. The container looks at the recipe for a named bean when asked and uses the configuration metadata encapsulated by that bean definition to create (or acquire) an actual object.

5 DI

Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other objects with which they work) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method.

DI exists in two major variants, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.

  • Constructor-based dependency injection: calling a static factory method is nearly equivalent.
  • Setter-based dependency injection: the container calls setter methods on your beans after invoking a no-argument constructor or a no-argument static factory method to instantiate your bean.

The Spring container can autowire relationships between collaborating beans.

Method injection is required when you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean("B") call to the container ask for (a typically new) bean B instance every time bean A needs it.

6 Bean Scopes

You can control the scope of the objects created from a particular bean definition. The Spring Framework supports six scopes, the late four are available only if you use a web-aware ApplicationContext. You can also create a custom scope.

  • singleton: (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
  • prototype: Scopes a single bean definition to any number of object instances.
  • request: Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition.
  • session: Scopes a single bean definition to the lifecycle of an HTTP Session.
  • application: Scopes a single bean definition to the lifecycle of a ServletContext.
  • websocket: Scopes a single bean definition to the lifecycle of a WebSocket.

When using annotation-driven components or Java configuration, the @RequestScope/@SessionScope/@ApplicationScope annotation can be used to assign a component to the request scope. For example:

1
2
3
4
5
@RequestScope
@Component
class LoginAction {
    // ...
}

The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.

7 Java-based Container Configuration

The central artifacts in Spring’s new Java-configuration support are @Configuration-annotated classes and @Bean-annoted methods.

The @Bean annotation is used to indicate that a method instantiates, configures, and initializes a new object to be managed by the Spring IoC container. Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class. The simplest possible @Configuration class reads as follows:

1
2
3
4
5
6
7
8
@Configuration
class AppConfig {

    @Bean
    fun myService(): MyService {
        return MyServiceImpl()
    }
}

it is equivalent to the following Spring <beans/> XML:

1
2
3
<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

you can use @Configuration classes as input when instantiating an AnnotationConfigApplicationContext.

1
2
3
4
5
6
7
import org.springframework.beans.factory.getBean

fun main() {
    val ctx = AnnotationConfigApplicationContext(AppConfig::class.java)
    val myService = ctx.getBean<MyService>()
    myService.doStuff()
}

You can enable component scanning with @ComponentScan(basePackages = ["example.com"​]) in a configuration class or call ctx.scan("example.com").

You can use AnnotationConfigWebApplicationContext when configuring the Spring ContextLoaderListener servlet listener, Spring MVC DispatcherServlet, and so forth.

Use @Scope annotation to specify scope.

The @Profile annotation lets you indicate that a component is eligible for registration when one or more specified profiles are active.