The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata file provided. The configuration metadata can be represented either by XML, Java annotations, or Java code. The following diagram is a high-level view of how Spring works. The Spring IoC container makes use of Java POJO classes and configuration metadata to produce a fully configured and executable system or application.
Spring provides following two distinct types of containers.
Spring provides following two distinct types of containers.
Spring BeanFactory Container
This is the simplest container providing basic support for DI and defined by the org.springframework.beans.factory.BeanFactory interface. The BeanFactory and related interfaces, such as BeanFactoryAware, InitializingBean, DisposableBean, are still present in Spring for the purposes of backward compatibility with the large number of third-party frameworks that integrate with Spring.
Spring ApplicationContext Container
ApplicationContext is used to represent Spring Container. It is built upon BeanFactory interface.
BeanFactory provides basic functionality while ApplicationContext provides advance features to our spring applications which make them enterprise level applications, like i18n, event publishing, JNDI access, EJB integration, Remoting etc.
ApplicationContext and Singleton beans:
While using BeanFactory, beans get instantiated when they get requested first time, like in getBean("bean_id") method, not when object of BeanFactory itself gets created. This is known as lazy-instantiation.
But while using ApplicationContext, singleton beans does not get created lazily. By default, ApplicationContext immediately instantiates the singleton beans and wire/set its properties as it's object itself gets created. So ApplicationContext loads singleton beans eagerly (pre-instantiated).
If we had used BeanFactory here, mybean would get instantiated when the method getBean(mybean) would be called.
But here with ApplicationContext, instantiation of bean with id mybean does not get delayed until getBean() method is called. If scope of the bean mybean is declared in configuration file as singleton, it will be immediately instantiated when we create ApplicationContext object acObj. So when getBean() would be called, mybean would already have got loaded and its dependencies set.
We can change this default behavior so that ApplicationContext does not load singleton beans eagerly by using lazy-init attribute as:
<bean id="mybean" class="x.y.z..MyBean" lazy-init="true"/>
A lazy-initialized bean tells the Spring to create a bean instance when it is first requested, rather than at the time of creation of ApplicationContext object.
=== > Write a simple Spring Application which will print "Hello World!" or any other message based on the configuration done in Spring Beans Configuration file.
- Maven Project
- add spring-core and spring-context dependency to pom.xml
- create source folder -> src/main/resources
- create spring configuration file named applicationContext.xml. You have to make sure that this file is available in CLASSPATH and use the same name in main application while creating application context.
- assign unique IDs to different beans.
<?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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
<!-- Error# Not Valid, it should be unique-->
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
<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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
<!-- Error# Not Valid, it should be unique-->
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
<!-- Valid -->
<bean id="helloWorldX" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
<bean id="helloWorldX" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
- first step is to create Application Context / Spring Container that loads spring configuration file and takes care of creating and initializing all objects/beans defined in configuration file.
- second step is to get required bean using getBean() method of created context. This method uses bean ID to return a generic object which finally can be casted to actual object. Once you have object, you can use this object to call any class method.
When Spring applicationcontext gets loaded into the memory, Framework makes use of the above configuration file to create and initialize all the spring beans defined and assign them a unique ID as defined in <bean> tag. You can use <property> tag to pass the values of different variables used at the time of object creation.
<bean id> <property>.. </property> </bean>
For spring to process annotations regardless of XML based, add the following lines in your spring bean configuration file.
<context:annotation-config />
<context:component-scan base-package="...specify your package name..." />
<context:component-scan base-package="...specify your package name..." />
Spring supports both Annotation based and XML based configurations. You can even mix them together. Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.
The default bean-name / id for a @Component or derivative (@Controller, @Service, etc.) is the unqualified class name with a lower first character. In order to have those two components together, just set a different bean name (for at least one of them):
@Component"secondFooComponent")
Bean Scope
When defining a <bean> in Spring, you have the option of declaring a scope for that bean.
1) to return a new bean instance each time one is needed, you should declare the bean's scope attribute to be prototype.
2) to return the same bean instance each time one is needed, you should declare the bean's scope attribute to be singleton.
3) return a single bean instance per HTTP request. *, you should declare the bean's scope attribute to be request.
4) return a single bean instance per HTTP session. *, you should declare the bean's scope attribute to be session.
5) return a single bean instance per global HTTP session. *, you should declare the bean's scope attribute to be globalSession.
In most cases, you may only deal with the Spring’s core scope – singleton and prototype, and the default scope is singleton.
* means only valid in the context of a web-aware Spring ApplicationContext
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="..." scope="singleton">
<!-- collaborators and configuration for this bean go here -->
</bean>
OR
@Service
@Scope("prototype")
@Scope("prototype")
Spring Beans are standard Java objects which are instantiated, initialized and managed by Spring Container.
Beans are mostly used to:
→ Configure Spring in some way (database connection parameters, security, and so on)
→ Avoid hard coding dependencies using dependency injection, so that our classes
remain self-contained and unit testable.
Spring Web MVC framework
DispatcherServlet/FrontController : Spring’s web MVC framework is designed around a central Servlet called DispatcherServlet that dispatches requests to controllers using handler mappings. Like a normal servlet DispatcherServlet also needs to be configured in the web deployement Descriptor(web.xml). By default DispatcherServlet Class will look for a name xxx-servlet.xml to load the Spring MVC configuration.
<web-app>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.
Upon initialization of a DispatcherServlet, Spring MVC looks for a configuration file named [servlet-name]-servlet.xml in the WEB-INF directory of your web application and creates the beans defined there, overriding the definitions of any beans defined with the same name in the global scope.
→ You can change the exact location of this configuration file through a Servlet initialization parameter. It is also possible to have just one root context for single DispatcherServlet scenarios.
This can be configured by setting an empty contextConfigLocation servlet init parameter, as shown below:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Spring - Bean Lifecycle
The life cycle of a Spring bean is easy to understand. When a bean is created, it may be required to perform some initialization to get it into a usable state. Similarly, when the bean is no longer required and is removed from the container, some cleanup may be required.
Though, there is lists of the activities that take place behind the scenes between the time of bean Instantiation and its destruction, but this chapter will discuss only two important bean lifecycle callback methods which are required at the time of bean initialization and its destruction.
To define setup and teardown for a bean, we simply declare the <bean> with init-method(@PostConstruct) and/or destroy-method(@PreDestroy) parameters. The init-method attribute specifies a method that is to be called on the bean immediately upon instantiation. Similarly, destroy-method specifies a method that is called just before a bean is removed from the container.
public class ExampleBean {
public void init() {
// do some initialization work
}
void destroy() throws Exception;
}
<bean id="exampleBean"
class="examples.ExampleBean"
init-method="init"
destroy-method="destroy"
/>
@Service
Annotate all your service classes with @Service. All your business logic should be in Service classes.
@Service
public class CompanyServiceImpl implements CompanyService {
...
}
@Repository
Annotate all your DAO classes with @Repository. All your database access logic should be in DAO classes.
@Repository
public class CompanyDAOImpl implements CompanyDAO {
...
}
@Component
Annotate your other components (for example REST resource classes) with @Component.
@Component
public class ContactResource {
...
}
@Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases, for example, in the persistence, service, and presentation layers, respectively.
@Autowired
Let Spring auto-wire other beans into your classes using @Autowired annotation.
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
...
}
Spring beans can be wired by name or by type.
@Autowire by default is a type driven injection. @Qualifier spring annotation can be used to further fine-tune autowiring.
@Resource (javax.annotation.Resource) annotation can be used for wiring by name.
Beans that are themselves defined as a collection or map type cannot be injected through @Autowired, because type matching is not properly applicable to them. Use @Resource for such beans, referring to the specific collection or map bean by unique name.
@Transactional
Configure your transactions with @Transactional spring annotation.
To activate processing of Spring's @Transactional annotation, use the
<tx:annotation-driven/> element in your spring's configuration file.
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
@Transactional
public Company findByName(String name) {
Company company = companyDAO.findByName(name);
return company;
}
...
}
The default @Transactional settings are as follows:
- Propagation setting is PROPAGATION_REQUIRED.
- Isolation level is ISOLATION_DEFAULT.
- Transaction is read/write.
- Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
- Any RuntimeException triggers rollback, and any checked Exception does not.
These default settings can be changed using various properties of the @Transactional spring annotation.
Specifying the @Transactional annotation on the bean class means that it applies to all applicable business methods of the class. Specifying the annotation on a method applies it to that method only. If the annotation is applied at both the class and the method level, the method value overrides if the two disagree.
@Scope
As with Spring-managed components in general, the default and most common scope for autodetected components is singleton. To change this default behavior, use @Scope spring annotation.
@Component
@Scope("request")
public class ContactResource {
...
}
Similarly, you can annotate your component with @Scope("prototype") for beans with prototype scopes.
Please note that the dependencies are resolved at instantiation time. For prototype scope, it does NOT create a new instance at runtime more than once. It is only during instantiation that each bean is injected with a separate instance of prototype bean.
Pluggability of other MVC implementations
Non-Spring MVC implementations are preferable for some projects. Many teams expect to leverage their existing investment in skills and tools, for example with JSF.
If you do not want to use Spring’s Web MVC, but intend to leverage other solutions that Spring offers, you can integrate the web MVC framework of your choice with Spring easily. Simply start up a Spring root application context through its ContextLoaderListener, and access it through its ServletContext attribute (or Spring’s respective helper method) from within any action object. No "plug-ins" are involved, so no dedicated integration is necessary. From the web layer’s point of view, you simply use Spring as a library, with the root application context instance as the entry point.
Your registered beans and Spring’s services can be at your fingertips even without Spring’s Web MVC. Spring does not compete with other web frameworks in this scenario. It simply addresses the many areas that the pure web MVC frameworks do not, from bean configuration to data access and transaction handling. So you can enrich your application with a Spring middle tier and/or data access tier, even if you just want to use, for example, the transaction abstraction with JDBC or Hibernate.