Spring Reference Notes
Quick Reference on Spring Framework Quick Reference on Spring Framework
Spring Framework
Spring, contextually speaking, is an application framework for the JVM. It uses a concept called Dependency Injection - as a general model for development, and it has changed how Java programs are written, even if the programs in question avoid the use of Spring itself.
Spring is also an ecosystem a galaxy of extensions and modules with a library called spring-core at its center. The extensions and modules add functionality and features to cover many, many possible use cases. In general, people don’t refer to spring-core much; instead they just use “Spring” and expect others to understand that the ecosystem as a whole is being referred to.
The Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure so one can focus on their application.
Spring enables to build applications from plain old Java objects (POJO's) and to apply enterprise services non-invasively to POJOs. This capability applies to the Java SE programming model and to full and partial Java EE.
Spring was built to make dependency injection easy. This software design pattern implies that dependent components delegate the dependency resolution to an external service that will take care of injecting the dependencies. The dependent component is not allowed to call the injector service and has very little to say when it comes to the dependencies that will be injected. This is why the behavior is also known as the “Don’t call us, we’ll call you!” principle, and it is technically known as inversion of control (IoC).
Inversion of control is a common characteristic of frameworks that facilitate injection of dependencies. And the basic idea of the dependency injection pattern is to have a separate object that injects dependencies with the required behavior, based on an interface contract.
POJO Programming Model
POJO means Plain Old Java Objects was first coined by Martin Fowler, Rebecca Parsons, and Josh MacKenzie to give regular Java objects an exciting-sounding name. It represents a programming trend that aims to simplify the coding, testing, and deployment phases of Java applications—especially enterprise Java applications.
Problem with Old EJB Programming
-
The Enterprise JavaBeans (EJB) technology was first announced around 1997. It offered a distributed business component model combined with a runtime platform that provided all the necessary middleware services those EJB components needed for their execution. It was a main specification under the J2EE specification umbrella at the time.
The EJB 2.x specification required that the component interface and business logic implementation class extend interfaces from the EJB framework package. These requirements created a tight coupling between the developer-written code and the interface classes from the EJB framework package. It also required the implementation of several unnecessary callback methods, such as `ejbCreate`, `ejbPassivate` and `ejbActivate` which are not directly related to the main design goal of EJB.
To develop an EJB component, need to write at least three different classes * for home, * for remote interfaces, and * for business objects.
public interface PetClinicService extends EJBObject {
public void saveOwner(Owner owner) throws RemoteException;
}
public interface PetClinicServiceHome extends EJBHome {
public PetClinicService create() throws RemoteException, CreateException;
}
public class PetClinicServiceBean implements SessionBean {
private SessionContext sessionContext;
public void ejbCreate() {
}
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void saveOwner() throws java.rmi.RemoteException {
//implementation of saving owner instance...
}
}
-
Testability was one of the biggest problems of the old EJB programming model. It was almost impossible o test session and entity bean outside the EJB container.
-
The deployment process was another time consuming and error-prone phase of the EJB programming model. Developers used deployment descriptor files in XML format to deploy developed EJB components, but configuring their middleware requirements, such as transaction semantics, security requirements, and so on, caused those files to become several hundred lines long.
-
Another problem of the old EJB programming model was that it diverted developers toward the procedural programming style. Application behavior in this style of programming is mainly handled within some methods, while data from and to those methods is carried with dumb domain model objects.
Benefits of POJO Programming
The most important advantage of the POJO programming model is that coding application classes is very fast and simple. This is because classes don’t need to depend on any particular API, implement any special interface, or extend from a particular framework class. Therefore no special callback methods needed until need them.
Because the POJO-based classes don’t depend on any particular API or framework code, they can easily be transferred over the network and used between layers.
Testing of these become easy and can be tested with any IDE with Junits. Also no framework needed for integration testing.
The POJO programming model lets you code with an object-oriented perspective instead of a procedural style. It becomes possible to reflect the problem domain exactly to the solution domain. Business logic can be handled over a more fine-grained model, which is also richer in terms of behavioral aspects.
Lightweight Containers and Inversion Of Control
It is much better to have an environment by which all different components needed will be created and wired and those required middleware services will be provided. Such an environment is called a container.
The Java EE platform provides several such containers, each specialized with services required by a particular layer in the application.
For example, the Servlet container creates and manages components of the web layer of an application, such as Servlets, JSPs, Filters, and so on.
The EJB container, on the other hand, focuses on the business layer of the application and manages the EJB components of it.
Similar to the Java EE platform, the Spring Container is also a container in which components of an application are created, wired with each other, and the middleware services are provided in a lightweight manner.
According to the book Expert One-on-One J2EE Development Without EJB by Rod Johnson and Jurgen Holler the containers should be capable of providing below services to the components managed in it environment.
Services:
-
Life-cycle management
-
Dependency resolution
-
Component lookup
-
Application configuration
In addition to those features, it will be very useful if the container is able to provide following middleware services:
-
Transaction management
-
Security
-
Thread management
-
Object and resource pooling
-
Remote access for components
-
Management of components through a JMX-like API
-
Extendibility and customizability of container
A lightweight container includes all of these features, but doesn’t require application code to depend on its own API.
Inversion Of Control (IoC)
-
One of the most important benefits containers that provide with components they manage is pluggable architecture.
-
Dependent components are never instantiated using a new operator within component classes.
-
IoC is one of the fundamental features that-is expected to be provided by any container and has basically two forms:
-
Dependency Lookup:
-
the container provides callback methods to the components it manages, and the components interact with the container and acquire their dependencies explicitly within those callback methods. In such a scenario, there is usually a lookup context that is used to access dependent components and other resources managed by the container.
The method used during the early years of J2EE corresponds to dependency lookup. The lookup context mentioned earlier was also called the JNDI context in this environment. EJB components and other resources such as JDBC DataSource and JMS ConnectionFactory were accessed through that JNDI context. Below depicts explicit interaction of various parts with the JNDI repository in the J2EE platform via JNDI API.
flowchart LR
Client[Servlet / EJB Client] -->|JNDI lookup()| JNDIContext[JNDI Context]
JNDIContext -->|search/bind| JNDIRepo[(JNDI Repository)]
JNDIRepo --> EJB[EJB Component]
JNDIRepo --> DS[JDBC DataSource]
JNDIRepo --> JMS[JMS ConnectionFactory]
Client -->|uses| EJB
Client -->|gets connection from| DS
Client -->|creates connection via| JMS
-
Dependency Injection:
Components are provided with suitable constructors or setter methods so that the container can inject dependent components. There is hardly ever an explicit lookup performed within components. Most of the time dependencies are injected during creation of components through those methods.
Dependency Injection
| The fundamental principle of dependency injection is that application objects should not be responsible for looking up the resources or collaborators on which they depend. Instead, an IoC container should handle object creation and dependency injection, resulting in the externalization of resource lookup from application code to the container. |
Benefits:
-
lookup logic is completely removed from application code, and dependencies can be injected into the target component in a pluggable manner.
-
Components don’t know the location or class of their dependencies. Therefore, unit testing of such components becomes very easy because there is no environmental dependency like the JNDI context, and dependent components can easily be mocked and wired up to the component in the test case.
Types of Dependency Injection
-
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.
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.
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. In Spring Constructor Injection cannot handle circular dependencies.
-
Setter or Constructor Injection:
IoC containers are expected to allow developers to mix the two type of dependency injection methods for the same component within the application configurations.