Spring Framework: Understanding spring

1. Overview

Official introduction of spring:

"The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.

A key element of Spring is infrastructural support at the application level: Spring focuses on the "plumbing" of enterprise applications so that teams can focus on application-level business logic, without unnecessary ties to specific deployment environments."

A comprehensive programming model based on a configuration model allows enterprise development teams to focus on business development.

"Features:

  • Core technologies: dependency injection, events, resources, i18n, validation, data binding, type conversion, SpEL, AOP.
  • Testing: mock objects, TestContext framework, Spring MVC Test, WebTestClient.
  • Data Access: transactions, DAO support, JDBC, ORM, Marshalling XML.
  • Spring MVC and Spring WebFlux web frameworks.
  • Integration: remoting, JMS, JCA, JMX, email, tasks, scheduling, cache.
  • Languages: Kotlin, Groovy, dynamic languages."

1.1 What is Spring ?

The Spring Framework is divided into modules. Applications can choose which modules they need. At the heart are the modules of the core container, including a configuration model and a dependency injection mechanism. Beyond that, the Spring Framework provides foundational support for different application architectures, including messaging, transactional data and persistence, and web. It also includes the Servlet-based Spring MVC web framework and, in parallel, the Spring WebFlux reactive web framework.

1.2 History of Spring and the Spring Framework

Spring came into being in 2003 as a response to the complexity of the early J2EE specifications. While some consider Java EE and Spring to be in competition, Spring is, in fact, complementary to Java EE. The Spring programming model does not embrace the Java EE platform specification; rather, it integrates with carefully selected individual specifications from the EE umbrella:

The Spring Framework also supports the Dependency Injection (JSR 330) and Common Annotations (JSR 250) specifications, which application developers may choose to use instead of the Spring-specific mechanisms provided by the Spring Framework.

Over time, the role of Java EE in application development has evolved. In the early days of Java EE and Spring, applications were created to be deployed to an application server. Today, with the help of Spring Boot, applications are created in a devops- and cloud-friendly way, with the Servlet container embedded and trivial to change. As of Spring Framework 5, a WebFlux application does not even use the Servlet API directly and can run on servers (such as Netty) that are not Servlet containers.

Spring continues to innovate and to evolve. Beyond the Spring Framework, there are other projects, such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, among others. It's important to remember that each project has its own source code repository, issue tracker, and release cadence. See spring.io/projects for the complete list of Spring projects.

1.3 Design Philosophy

When you learn about a framework, it's important to know not only what it does but what principles it follows. Here are the guiding principles of the Spring Framework:

Provide choice at every level. Spring lets you defer design decisions as late as possible. For example, you can switch persistence providers through configuration without changing your code. The same is true for many other infrastructure concerns and integration with third-party APIs.

Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about how things should be done. It supports a wide range of application needs with different perspectives.

Maintain strong backward compatibility. Spring's evolution has been carefully managed to force few breaking changes between versions. Spring supports a carefully chosen range of JDK versions and third-party libraries to facilitate maintenance of applications and libraries that depend on Spring.

Care about API design. The Spring team puts a lot of thought and time into making APIs that are intuitive and that hold up across many versions and many years.

Set high standards for code quality. The Spring Framework puts a strong emphasis on meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean code structure with no circular dependencies between packages.

2. Core Technology

IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.

2.1 The IoC Container

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) 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. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework's IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory. It adds:

  • Easier integration with Spring's AOP features
  • Message resource handling (for use in internationalization)
  • Event publication
  • Application-layer specific contexts such as the WebApplicationContext for use in web applications.

In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory.

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

The org.springframework.context.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. It lets you express the objects that compose your application and the rich interdependencies between those objects.

Translation and understanding: Configuration metadata can be built using XML configuration, Java annotations, and Java code (XML is the traditional format for defining configuration metadata). Configuration metadata means that the application developer tells the Spring container to instantiate, configure, and assemble objects in the application.XML-based configuration metadata configures these beans as <beans/>elements in the top-level elements.Java configuration typically uses the @Bean annotated method in the @configuration class.These bean definitions correspond to the actual objects that make up the application.Usually, fine-grained domain objects are not configured in containers, since it is usually the responsibility of dao and business logic to create and load domain objects.

The following example is the basic structure of XML-based configuration metadata:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>

Introduction:

  • The id property is a string that identifies a single bean definition.The value of the id attribute can also be the bean id of the reference object
  • The class attribute defines the type of the bean and uses a fully qualified class name.

Instantiating a Container

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.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Services.xmlandDaos.xmlIs metadata based on XML configuration
Writing XML-based configuration metadata
Often there are multiple XML files, and each individual XML configuration file represents a logical layer or module in the architecture.

Using 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 requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example shows:

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

Beans

A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container (for example, in the form of XML <bean/> definitions).

In the container itself, these bean definitions are represented as BeanDefinition objects that contain (among other things) the following metadata:

  • Package qualified class name: The actual implementation class of the bean s that are usually defined.
  • Bean Behavior Configuration Element, which describes the behavior of beans in containers (scope, life cycle callbacks, and so on).
  • References to other beans required by a bean to perform its work.These references are also known as collaborators or dependencies.
  • Other configuration settings to set in newly created objects -such as the size limit of the pool or the number of connections to use in bean s that manage connection pools.
    This metadata is translated into a set of properties that make up each bean definition.

These attributes are:

  • Class
  • Name
  • Scope
  • Constructor arguments
  • Properties
  • Autowiring mode
  • Lazy initialization mode
  • Initialization metho
  • Destruction method

Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the extra ones can be considered aliases.

Alias Beans outside of Bean Definition

<alias name="fromName" alias="toName"/>

If you use Javaconfiguration, the @Bean annotation can be used to provide aliases

Instantiating Beans

Dependency Injection

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. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes or the Service Locator pattern.

Dependent injection is a process in which objects define their dependencies (that is, other objects they use) only through constructor parameters, factory method parameters, or properties set on the object instance after it is constructed or returned from the factory method.

Code is cleaner with the DI principle, and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies.

Using the DI principle, code is cleaner and decoupling is more efficient when objects have their dependencies.Objects do not look for their dependencies, nor do they know their location or class.
DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.
Constructor-based Dependency Injection

Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency. Calling a static factory method with specific arguments to construct the bean is nearly equivalent

Constructor-based DI is achieved by calling a constructor with multiple parameters from a container, each representing a dependency.Calling static factory methods with specific parameters to construct bean s is almost equivalent.
Constructor Argument Resolution
Reference Injection

<beans>
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg ref="beanTwo"/>
        <constructor-arg ref="beanThree"/>
    </bean>

    <bean id="beanTwo" class="x.y.ThingTwo"/>

    <bean id="beanThree" class="x.y.ThingThree"/>
</beans>

Type matching

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

Index

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

Name

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

Setter-based Dependency Injection

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...
}

Constructor-based or setter-based DI?

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.

  • Use constructors for mandatory dependencies
  • Use setter or configuration methods for optional dependencies
  • The Spring team typically supports constructor injection because it allows you to implement application components as immutable objects and ensure that required dependencies are not empty.
  • One benefit of setter injection is that the setter method allows objects of this class to be reconfigured or reinjected later.
  • When dealing with third-party classes that do not have source code, you are given a choice.For example, if a third-party class does not expose any setter methods, constructor injection may be the only available form of DI.

Circular dependencies
Circular Dependency
One possible solution is to edit the source code of some classes that are configured by setters rather than constructors.Alternatively, avoid constructor injection and use setter injection only.In other words, although this is not recommended, you can configure circular dependencies using setter injection.

Lazy-initialized Beans

By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the configuration or surrounding environment are discovered immediately, as opposed to hours or even days later. When this behavior is not desirable, you can prevent pre-instantiation of a singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.

Containers default to creating a single instance of a class immediately, and can prevent the pre-instantiation of a single bean by marking the bean definition as delayed initialization.Delayed initialization beans tell the IoC container to create a bean instance on the first request rather than at startup.

in XML, this behavior is controlled by the lazy-init attribute on the element, as the following example shows:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>

You can also control lazy-initialization at the container level by using the default-lazy-init attribute on the element, a the following example shows:

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

Autowiring Collaborators

Tags: Java Spring xml Attribute

Posted on Wed, 20 May 2020 00:12:03 -0400 by rallen102