Core Concepts Of The Spring Framework
Core Concepts Of The Spring Framework
Spring is lightweight solution for building enterprise application. It's an alternative to Java EE. As example, in web application, Spring application only need a servlet container (Tomcat, Jetty) instead of a full-blown Java Application server (JBoss, Weblogic, etc) like Java EE application does.
Here some core concepts behind Spring Framework:
- Dependency Injection(DI) and Inversion of Control (IoC): Spring works as an IoC container. This container enable DI process, which an instance of service implementations are injected into a target object's properties (where this property is ideally an interface type) via constructors/setters, instead of target object creating (instantiate) the instance themselves. In this approach, the application objects are just a simple POJO (Plain Old Java Object) which can be used in different service implementations for different environments (web and/or standalone application like batch, etc). This helps to achieve loose coupling by wiring of independent components/objects.
- Aspect Oriented Programming (AOP): AOP breaks the program logic into distinct parts (called concerns). It is used to increase modularity by cross-cutting concerns. A cross-cutting concern is a concern that can affect the whole application and should be centralized in one location in code as possible, such as transaction management, authentication, logging, security, etc.
Spring IoC Container
The Spring container is at the core of the Spring Framework. The container will create the objects, wire them together, configure them, and manage their complete life cycle from creation till destruction. The Spring container uses dependency injection (DI) to manage the components that make up an application.
The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework's IoC container:
- 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; and 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 (as a complete superset of the BeanFactory) adds more enterprise-specific functionality.
Let's look slightly deeper what's the difference between those two. Below are or sample codes:
package com.dariawan.bean;
public class Footer {
private String signature;
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
}
<?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.xsd">
<bean id="footer" class="com.dariawan.bean.Footer">
<property name="signature" value="Just another Java programmer"/>
</bean>
</beans>
We have same class Footer and beans.xml configuration. But we can choose our container, either BeanFactory or ApplicationContext:
package com.dariawan.app;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.dariawan.bean.Footer;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
public class SpringBeanFactoryApp {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
Resource resource = new ClassPathResource("beans.xml");
reader.loadBeanDefinitions(resource);
Footer footer = beanFactory.getBean("footer", Footer.class);
System.out.println(footer.getSignature());
}
}
package com.dariawan.app;
import com.dariawan.bean.Footer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringApplicationContextApp {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
Footer footer = appContext.getBean("footer", Footer.class);
System.out.println(footer.getSignature());
}
}
BeanFactory or ApplicationContext?
Feature | BeanFactory | ApplicationContext |
---|---|---|
Bean instantiation/wiring | Yes | Yes |
Automatic BeanPostProcessor registration | No | Yes |
Automatic BeanFactoryPostProcessor registration | No | Yes |
Convenient MessageSource access (for i18n) | No | Yes |
ApplicationEvent publication | No | Yes |
Short version: use an ApplicationContext unless you have a really good reason for not doing so.
Spring ApplicationContext
The ApplicationContext is the central interface within a Spring application for providing configuration information to the application. It is read-only at run time, but can be reloaded if necessary and supported by the application.
The ApplicationContext provides:
- Bean factory methods for accessing application components.
- The ability to load file resources in a generic fashion.
- The ability to publish events to registered listeners.
- The ability to resolve messages to support internationalization.
- Inheritance from a parent context.
The Spring IoC container
The interface ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration instructions (metadata).
Those configuration can be represented in:
- XML
- Java annotations, or
- Java code
Spring Bean
Any normal Java class that is instantiated, assembled, and otherwise managed by a Spring IoC container is called Spring Bean. These beans are created with the configuration metadata that you supply to the container, and as the result: we can use spring application context to get Spring Bean instance. Spring IoC Container manages the lifecycle of Spring Bean scope and injecting any required dependencies in the bean.
- singleton: a single instance of the bean will get created per IoC container, hence the singleton beans are not thread safe. Singleton is the default scope of Spring bean.
- prototype: a new instance will get created every-time the bean is requested, hence any number (or unlimited) of object instances can be created.
- request: a single bean definition to the lifecycle of a single HTTP request; that is each and every HTTP request will have 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: a single bean definition to the lifecycle of a HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
- global-session: a single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a portlet context. Only valid in the context of a web-aware Spring ApplicationContext.
- custom: You can define your own rules and a new scope name (advanced features)
Spring also has other more specialized scope:
- Web socket scope
- Refresh scope
- Thread scope (defined but not registered by default)
In most cases, we only deal with the Spring’s core scope – singleton and prototype.
Let's continue to use Footer class for our example...
Singleton Scope Bean
<?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.xsd">
<bean id="footer" class="com.dariawan.bean.Footer" />
</beans>
package com.dariawan.app;
import com.dariawan.bean.Footer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringSingletonBeanApp {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans-singleton.xml");
Footer footer1 = appContext.getBean("footer", Footer.class);
footer1.setSignature("Just another Java programmer");
System.out.println(footer1.getSignature());
Footer footer2 = appContext.getBean("footer", Footer.class);
System.out.println(footer2.getSignature());
footer2.setSignature("Hello world! @Dariawan");
System.out.println(footer1.getSignature());
}
}
/*
Output:
------
Just another Java programmer
Just another Java programmer
Hello world! @Dariawan
*/
footer1 and footer2 referencing to the same instance of Footer. That's because bean footer is a singleton, only one instance active in the container.
Prototype Scope Bean
<?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.xsd">
<bean id="footer" class="com.dariawan.bean.Footer" scope="prototype" />
</beans>
You can see the difference between beans-prototype.xml and beans-singleton.xml, bean footer in beans-prototype.xml scope is declared as prototype.
package com.dariawan.app;
import com.dariawan.bean.Footer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringPrototypeBeanApp {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans-prototype.xml");
Footer footer1 = appContext.getBean("footer", Footer.class);
footer1.setSignature("Just another Java programmer");
System.out.println(footer1.getSignature());
Footer footer2 = appContext.getBean("footer", Footer.class);
System.out.println(footer2.getSignature());
footer2.setSignature("Hello world! @Dariawan");
System.out.println(footer2.getSignature());
}
}
/*
Output:
------
Just another Java programmer
null
Hello world! @Dariawan
*/
In prototype; footer1 and footer2 are referencing to difference instance of Footer.