Spring Framework
Quick Reference on Spring Framework Quick Reference on Spring Framework
Spring IOC Container
-
The core of the Spring Application Framework is its Inversion of Control (IoC) Container.
-
Its job is to instantiate,
-
initialize, and
-
wire up objects of the application,
-
as well as provide lots of other features available in Spring throughout an object’s lifetime.
-
The objects that form the backbone of the application, and are managed by
Spring Container, are calledbeans. They are ordinary Java objects also known as POJOs—but they are instantiated, assembled by the Spring Container, and managed within it.
The Spring Container expects information that are needed to instantiate beans and to specify how to wire them together. This information is called configuration metadata. Together with this configuration metadata, the Spring Container takes classes written in the application and then creates and assembles beans in it.
-
Spring allows Annotation-based, Java-based configuration metadata and thru configuration metadata in XML allows mix-match of the configuration metadata format.
| The nice thing is that the Spring Container is independent of the configuration metadata format. |
Configuring and Using the Container
The Spring Container is also a Java object, which is created in the application at some specific point and then allowed to manage the rest of the application. Instantiation of Spring Container can be done in basically two different ways.
-
In standalone applications, you use the programmatic approach.
-
In web applications, on the other hand, the declarative approach is preferable with the help of some configuration within the web.xml file.
| In a big project, it’s a good idea to divide configuration metadata into several different les so that it can be managed easily and can be managed by different developers at the same time. This division usually reflects the layers of the application. |
-
Any bean marked as
org.springframework.context.annotation.Configurationannotation tells Spring that this class contains configuration metadata as well as itself as a bean. Within the configuration class, created factory methods marked with theorg.springframework.context.annotation.Beanannotation. -
Those methods are called by the Spring Container during bootstrap, and their returning values are treated as Spring-managed beans.
-
The method name is accepted as the bean name by default.
-
Within a factory method, we created a bean using its concrete class and returned it after setting its necessary dependencies by calling its setter methods. Dependencies can also be given as constructor arguments.
-
The return type of the factory methods are defined as interface instead of the concrete classes.
@Configuration
public class BeanConfiguration {
@Bean
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
bean.setAccountDao(accountDao());
return bean;
}
@Bean
public AccountDao accountDao() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
}
-
The next step is to create the Spring Container instance and ready to use after its creations.
-
The process of obtaining Spring-managed beans from Spring Container is called “bean lookups.”
Dependency Injections
Setter Injection
-
Setter injection is performed after a bean instance is created.
-
All properties defined in the configuration metadata of the bean are injected by calling setter methods corresponding to those properties.
-
Also, it is possible to inject other bean dependencies and primitive values,
strings,classes,enums, and so on.
<bean id="accountService" class="org.springLearning.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="account1" class="org.springLearning.Account">
<property name="id" value="1" />
<property name="ownerName" value="John" />
<property name="balance" value="10.0"/>
<property name="locked" value="false" />
</bean>
<bean id="accountDao" class="org.springLearning.AccountDaoInMemoryImpl">
<property name="accountsMap">
<map>
<entry key="1" value-ref="account1"/>
<entry key="2" value-ref="account2"/>
</map>
</property>
</bean>
-
Spring handles necessary type conversions as much as possible.
-
Spring allows to inject
CollectionorMapvalues as well.
**
Constructor Injection
-
Constructor injection is performed during component creation.
-
Dependencies are expressed as constructor arguments, and the container identifies which constructor to invoke by looking at types of those constructor arguments specified in the bean definition.
-
Similar to setter injection, we can also provide straight values like
int,Boolean,String,Enum, and so on, in addition to references to other beans. The <constructor-arg> element accepts the value attribute to inject those values. The necessary conversions are handled by the Spring Container.
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public AccountServiceImpl(AccountDao accountDao) {
this.accountDao = accountDao;
}
//...
<bean id="accountService" class="org.springLearning.AccountServiceImpl">
<constructor-arg ref="accountDao"/>
</bean>
}
Circular Dependencies
-
One disadvantage of constructor injection is that it cannot handle circular dependencies.
-
Although Spring allows circular dependencies using setter injection,
Dependency Resolution Process
-
The Spring Container’s bootstrap process can be divided into roughly two main phases.
-
In the first phase, the container processes configuration metadata and builds up bean definitions that exist in the metadata. At this step, it also validates those bean definitions..
-
In the second phase, bean creations are performed, and then dependency injections are performed. Actually,not all beans are created; only
singleton-scopedbeans are created during the container bootstrap process.
-
-
A bean is not injected as a dependency before it is first fully created and its own dependencies are injected. Therefore, the bean dependencies that are injected into a bean are fully configured and ready to use within the target bean. An exception for this is related to circular dependencies.
Overriding Bean Definitions
-
It is possible to override a bean definition in the Spring Container.
-
Beans have identities identified by there
names. -
If we create a bean definition with a name that is already given to some other bean definition, the second definition overrides the first one.
-
The Spring Container provides two different forms of the bean override mechanism.
-
The first is on the bean configuration metadata file level. It is possible to divide configuration metadata into several different files or classes, and then you can specify them together during creation of
ApplicationContext. In this case, the Spring Container merges all those bean definitions coming from different configuration sources. During this merge, the order of configuration sources given to the container becomes important. -
The second form of bean override is on the container level.
ApplicationContextcan have the parentApplicationContext, and it is possible to have two bean instances with the same name coexisting in both parent and childApplicationContextinstances. In that case, when we refer to thebeanwith the repeating name, Spring provides the bean defined in the childApplicationContext.
-
ApplicationContext hierarchies are common for web applications.
In short, parent ApplicationContext in a web application is usually created using org.springframework.web.context.ContextLoaderListener, and child ApplicationContext is created by Spring MVC DispatcherServlet. DispatcherServlet identifies the ApplicationContext instance created by the ContextLoaderListener if it’s available, and it uses it as the parent ApplicationContext during its own ApplicationContext instance creation.
|
Using the depends-on Attribute
-
If two bean definitions that have no dependency on each other, either directly or indirectly, the order of their creation is internal to the Spring Container.
-
In certain scenarios if needed, we can define
depends-on(for XML configuration) ororg.springframework.context.annotation.DependsOn@DependsOnannotations to specify thatbean bshould be created beforebean a.
<bean id="a" class="org.springLearning.A" depends-on="b,c"/>
Autowiring
-
we can let the Spring Container inject them to your beans automatically. This is called autowiring. It is useful especially during development because bean definitions need to be updated as the codebase evolves.
Autowiring has three modes: byType, byName, and constructor.
-
byType:In autowiring
byType, Spring investigates properties of a bean definition by looking at its class via Java reflection and tries to inject available beans in the container to the matching properties by their types. It performs injection by calling setter methods of those properties.If more than one bean instance autowiring candidates are suitable for injection to a specific property, dependency injection fails. The Spring Container needs a bit of help from you to decide which one to inject. One way is to exclude other beans from autowiring candidates, and the remaining bean is injected by the container. You can use the
autowire-candidateattribute of the<bean>element for this purpose -
byName:The other option is to use autowiring mode
byName.If we have several candidate beans. In that case, the container tries to match the property name with the bean name that it will be injected into -
constructor:The third mode is
constructor. It is very similar tobyType, but in this case the Spring Container tries to find beans whose types match with constructor arguments of the bean class.
If there is more than one candidate, it fails as expected. In that case, we need to tell the container which specific bean it should auto-inject into the target bean. Spring provides the org.springframework.beans.factory.annotation.Qualifier annotation for this purpose.
Annotation-based bean configuration also makes use of the @Autowired and @Qualifier annotations to enable autowiring. Use of the @Autowired and @Qualifier annotations is the same as in Java-based configuration.
* However, if we want to assign a specific qualifier value other than the bean name, you need to place the @Qualifier annotation on top of the class with the @Component annotation.
-
Another nice feature related to autowiring in Java- and annotation-based configurations is that
@Autowiredon fields. This removes the necessity of having setter methods for setter injection. -
In such a case, the Spring Container performs dependency injection by direct field access using the
Java Reflection API. -
Autowiringis only for dependencies to other beans. It doesn’t work for straight values, such asint,boolean,String,Enum, and so on. -
For such properties, you can use the
org.springframework.beans.factory.annotation.Valueannotation either on the field level or on the setter method level. The@Valueannotation accepts a String value to specify the value to be injected into the built-in Java typed property. Necessary type conversion is handled by the Spring Container. The@Valueannotation can also be used for expression-driven dependency injection.
Bean Lookups
In any Spring-enabled application, the aim should be increasing the number of Spring-managed beans as much as possible and decreasing the number of other objects that are outside the control of the Spring Container.
However, no matter how hard you try, you come to a point at which you need to access beans from other objects not under control of the Spring Container. In such cases, those objects should first obtain a reference to the ApplicationContext instance in the environment.
-
For standalone applications, this is a task that should be handled by the developers explicitly. For example, they can assign the ApplicationContext instance to a static variable that is globally accessible right after its creation.
-
For web applications, Spring provides a utility class called
org.springframework.web.context.support.WebApplicationContextUtils, which has methods that return theApplicationContextof the web application.
In any case, after obtaining a reference to the ApplicationContext instance, we can perform explicit bean lookups via various getBean() methods available in the ApplicationContext interface.
Spring Managed Beans
Naming Beans
-
Beans are identified by their
names. -
They have at least one name if not defined by
idattribute the Spring Container assigns an internal name.
<bean name="accountDao,accountDaoInMemory"
class="org.springLearning.AccountDaoInMemoryImpl"/>
</bean>
@Configuration
public class Ch2BeanConfiguration {
@Bean(name={"accountDao,accountDaoInMemory"})
public AccountDao foo() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
//...
}
Bean Instantiation Methods
-
The most common way to create beans is to invoke one of the
constructorsavailable in their classes or by factory method.
<!-- if class have constructor with arguments -->
<bean id="foo1" class="org.springLearning.Foo">
<property name="name" value="foo1"/>
</bean>
<bean id="foo2" class="org.springLearning.Foo">
<constructor-arg value="foo2"/>
</bean>
-
The second option for creating beans is to invoke the static or instance factory methods that are available.
-
In Java Annotation based use
@Componentson the class to let spring know and can manage.
Bean Scopes
-
The lifetime of beans created by the Spring Container is called bean scope.
-
By default, all beans created by the Spring Container have singleton scope and to that container.
-
The second scope supported by Spring is
prototype. It is very similar to creating an object using thenewoperator in Java code. Beans with the prototype scope are created whenever they are accessed in the container, either from other bean definitions via bean reference, or from within the application code with explicitbean lookupusing theApplicationContext.getBean()method.
| Sometimes a singleton-scoped bean may depend on a prototype-scoped bean, and it may expect to deal with a new instance whenever it uses the prototype-scoped bean in its method calls. Bean dependencies, however, are injected at bean creation time, and because the singleton-scoped bean is created and its dependencies are injected only once in its lifetime, its prototype scope dependency is created once at that time and injected into it. After that time, no new prototype instance is created and injected into that singleton-scoped bean. Practically, prototype scope in that case behaves like singleton scope. To overcome this limitation, you have to give up the dependency injection feature provided by the Spring Container and perform explicit bean lookup within the singleton scope instance whenever you need a new prototype instance. |
-
requestandsessionScope. They can only be used in web applications. -
Attempting to use them in a standalone application causes the Spring Container not to bootstrap.
-
A
request-scopedbean is created every time a new web request arrives at the application, and that same bean instance is used throughout the request. -
A
session-scopedbean, as you may have already guessed, is created each time a new HTTP Session is created, and that instance stays alive as the session stays alive.
| Column 1, Scope | Column 2, Description |
|---|---|
|
(Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
|
Scopes a single bean definition to any number of object instances. |
|
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. Only valid in the context of a web-aware Spring ApplicationContext. |
|
Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext. |
|
Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext. |
|
Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext. |
Lazy Initialization
-
The Spring Container, by default, creates beans during its startup. This is called eager bean initialization. Its advantage is that you can see configuration errors as early as possible.
-
Spring also supports lazy bean initialization. If beans are configured by developers to be created lazily, the container delays their creation until they are really needed. Their creation is triggered either by a reference made from another bean that is already being created or by an explicit bean lookup performed from within application code.
-
The advantage of lazy bean creation is that it speeds container bootstrap time and has a smaller memory footprint. On the other hand, if bean configuration errors exist in the metadata, they may remain unnoticed until their scenarios are tested.
Life-Cycle Callbacks
-
Beans can define callback methods, which can be invoked by the container at specific points during their lifetime. Those points are after their instantiation and just before termination of their defined scopes.
-
They are also called
initanddestroymethods. -
The
initmethod is invoked by the container after the bean is created, and its properties are injected. Because the bean instance is ready to use, you can perform anything within the init method in which the bean’s properties are involved. -
The
destroymethod is invoked just before the end of a bean’s lifetime. -
Because the lifetime of beans is changeable according to their scopes, the invocation of destroy methods may be occur at different times.
-
The
destroymethods of singleton-scoped beans are invoked at the shutdown of the whole Spring Container. -
The destroy methods of request-scoped beans are invoked at the end of the current web request.
-
The
destroymethods of session-scoped beans are invoked atHTTP sessiontimeout or invalidation. -
Prototype-scoped beans, are not tracked after their instantiation; therefore, their destroy methods cannot be invoked. -
Method names can be anything. There is no restriction; however, methods should return void and accept nothing as input arguments. They can throw any type of exception.
-
Spring also supports the JSR-250 Common Java annotations
javax.annotation.PostConstructandjavax.annotation.PreDestroy. When they are placed on top ofinitanddestroymethods, they are invoked at bean creation and destruction times as well. -
There is no restriction on the names of those methods. The method names can be anything as long as they are annotated properly
@PostConstruct@PreDestroy. -
There is a third option for life-cycle callback methods.
-
The Spring Framework provides two special interfaces called
org.springframework.beans.factory.InitializingBeanandorg.springframework.beans.factory.DisposableBean. They declareafterPropertiesSet()anddestroy()methods, respectively. -
If a bean implements the
InitializingBeaninterface, the Spring Container calls itsafterPropertiesSet()method just after injection of its properties. -
Similarly, if a bean implements the
DisposableBeaninterface, its destroy method is called just before the bean’s destruction time