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 called beans. 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.

Diagram
  • 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.

  1. In standalone applications, you use the programmatic approach.

  2. 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.Configuration annotation tells Spring that this class contains configuration metadata as well as itself as a bean. Within the configuration class, created factory methods marked with the org.springframework.context.annotation.Bean annotation.

  • 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 Collection or Map values 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,

Diagram

Dependency Resolution Process

  • The Spring Container’s bootstrap process can be divided into roughly two main phases.

    1. 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..

    2. In the second phase, bean creations are performed, and then dependency injections are performed. Actually,not all beans are created; only singleton-scoped beans 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.

    1. 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.

    2. The second form of bean override is on the container level. ApplicationContext can have the parent ApplicationContext, and it is possible to have two bean instances with the same name coexisting in both parent and child ApplicationContext instances. In that case, when we refer to the bean with the repeating name, Spring provides the bean defined in the child ApplicationContext.

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) or org.springframework.context.annotation.DependsOn @DependsOn annotations to specify that bean b should be created before bean 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.

  1. 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-candidate attribute of the <bean> element for this purpose

  2. 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

  3. constructor:

    The third mode is constructor. It is very similar to byType, 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 @Autowired on 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.

  • Autowiring is only for dependencies to other beans. It doesn’t work for straight values, such as int, boolean, String, Enum, and so on.

  • For such properties, you can use the org.springframework.beans.factory.annotation.Value annotation either on the field level or on the setter method level. The @Value annotation 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 @Value annotation 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.

Diagram

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.

  1. 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.

  2. For web applications, Spring provides a utility class called org.springframework.web.context.support.WebApplicationContextUtils, which has methods that return the ApplicationContext of 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 id attribute 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 constructors available 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 @Components on 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 the new operator 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 explicit bean lookup using the ApplicationContext.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.
  • request and session Scope. 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-scoped bean is created every time a new web request arrives at the application, and that same bean instance is used throughout the request.

  • A session-scoped bean, 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.

Table 1. Bean Scope
Column 1, Scope Column 2, Description

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. Only valid in the context of a web-aware Spring ApplicationContext.

session

Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.

application or globalSession

Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.

websocket

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 init and destroy methods.

  • The init method 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 destroy method 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 destroy methods 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 destroy methods of session-scoped beans are invoked at HTTP session timeout 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.PostConstruct and javax.annotation.PreDestroy. When they are placed on top of init and destroy methods, 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.InitializingBean and org.springframework.beans.factory.DisposableBean. They declare afterPropertiesSet() and destroy() methods, respectively.

  • If a bean implements the InitializingBean interface, the Spring Container calls its afterPropertiesSet() method just after injection of its properties.

  • Similarly, if a bean implements the DisposableBean interface, its destroy method is called just before the bean’s destruction time

Bean Definition Profiles

  • Bean definition profiles can be used to define beans according to the runtime environment, and how Environment abstraction can help in configure active profiles and placeholder variables specific to the application. This is achieve by @Profile annotations.