Spring Framework — Spring Core

Chinmaya Sahoo
6 min readDec 14, 2020

Spring simplifies java development by managing dependencies. Spring and J2EE have same feature set. However, in early days EJBs (Enterprise Java Beans) was complex to use and slow. That’s why Spring framework was emerged.

Inversion Of Control

By contrast with traditional programming, in which our custom code makes calls to a library, IOC enables a framework to take control of the flow of a program and make calls to our custom code.

Dependency Injection

Dependency Injection is the act of connecting objects with other objects, (or “injecting” objects into other objects), is done by an assembler rather than by the objects themselves.

Two most common injections are;

  1. Constructor injection — dependencies are injected when creating the object.
  2. Setter injection — dependencies are injected by calling setter methods of the object.

Spring IOC container

The Spring container is responsible for instantiating, configuring, and assembling the Spring beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets you express the objects that compose your application and the rich inter-dependencies between those objects.

The responsibilities of IOC container are:

  • Instantiating the bean
  • Wiring the beans together
  • Configuring the beans
  • Managing the bean’s entire life-cycle

The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IOC container. Spring framework provides two distinct types of containers.

  1. BeanFactory container
  2. ApplicationContext container

BeanFactory is the root interface of Spring IOC container. ApplicationContext is the child interface of BeanFactory.

One main difference between BeanFactory and ApplicationContext is that BeanFactory only instantiates bean when we call getBean() method while ApplicationContext instantiates singleton bean when the container is started, It doesn’t wait for getBean() method to be called.

How to Create a Spring Container?

Spring provides many ApplicationContext interface implementations that we use are —

  1. AnnotationConfigApplicationContext: If we are using Spring in standalone Java applications and using annotations for Configuration, then we can use this to initialize the container and get the bean objects.
  2. ClassPathXmlApplicationContext: If we have spring bean configuration XML file in a standalone application, then we can use this class to load the file and get the container object.
  3. FileSystemXmlApplicationContext: This is similar to ClassPathXmlApplicationContext except that the XML configuration file can be loaded from anywhere in the file system.

AnnotationConfigWebApplicationContext and XmlWebApplicationContext for web applications.

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

here we are making configuration metadata via applicationContext.xml file(XML-based configuration).

AnnotationConfigApplicationContext  context = new AnnotationConfigApplicationContext(AppConfig.class);

here we are making configuration metadata via AppConfig.class file.

Let us see BeanFactory configuration

XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource("applicationContext.xml"));

Bean Scope

Bean scope refers to the life cycle of the bean. Default scope for a bean is a Singleton. Reference to a Singleton bean will be kept in the bean factory. Another common scope is prototype beans. Prototype bean instances are not stored in bean factory therefore, garbage collection will happen once the client object is done with the bean. Also pre-destroy methods will not be called on prototype beans.

Spring framework supports following bean scopes:

  • singleton: (Default) Scopes a single bean definition to a single object instance per 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: 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.

Annotation-based Container Configuration

Starting from Spring 2.5 it became possible to configure the dependency injection using annotations. So instead of using XML to describe a bean wiring, you can move the bean configuration into the component class itself by using annotations on the relevant class, method, or field declaration.

Why Spring Configuration with Annotations?

  1. XML configuration can be verbose
  2. Easy to configure your Spring beans with Annotations
  3. Annotations minimize the XML configuration

Annotation wiring is not turned on in the Spring container by default. So, before we can use annotation-based wiring, we will need to enable it in our Spring configuration file. So consider the following configuration file in case you want to use any annotation in your Spring application.

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context = "http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config/>
<!-- bean definitions go here -->

</beans>

After configuration spring provides many annotations that we can use, Let us see and discuss:

  • @Required
  • @Autowired
  • @Qualifier
  • @Primary
  • @Resource
  • @PostConstruct and @PreDestroy

@Required

The @Required annotation is method-level annotation and applied to the setter method of a bean.
This annotation simply indicates that the setter method must be configured to be dependency-injected with a value at configuration time.

@Autowired

We can use the @Autowired to mark a dependency which Spring is going to resolve and inject. We can use this annotation with a constructor, setter, or field injection.

Constructor Injection

class Car {
private Engine engine;

@Autowired
Car(Engine engine) {
this.engine = engine;
}
}

Setter injection

class Car {
private Engine engine;

@Autowired
void setEngine(Engine engine) {
this.engine = engine;
}
}

Field injection

class Car {
@Autowired
private Engine engine;
}

@Qualifier

We use @Qualifier annotation to resolve ambiguous dependencies. When there are multiple beans with same type then we can use this annotation and the search will happen by the name of bean.

If there are multiple implementations for a single interface then we can use @Qualifier to choose required implementation at runtime.

@Autowired 
@Qualifier("datasource")
private DataSource datasource;

@Autowired
@Qualifier("datasource1")
private DataSource datasource;

@Resource

Spring also supports injection using the JSR-250 @Resource annotation on fields or bean property setter methods.

public class SimpleMovieLister {

private MovieFinder movieFinder;

@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}

If no name is specified explicitly, the default name is derived from the field name or setter method.

@PostConstruct and @PreDestroy

We can add initialization methods using @PostConstruct annotation

@PostConstruct
public void init(){
//some initialization work
}

We can add cleanup methods using @PreDestroy annotation.

@PreDestroy
Public void cleanUp(){
//some initialization work
}

Java-based Container Configuration

The central artifacts in Spring’s new Java-configuration support are @Configuration-annotated classes and @Bean-annotated methods.

@Configuration

To Configure the Application context we define a class with @Configuration annotation. In this class we can define beans. This type of configuration is called Java source code based configuration.

@Bean

@Bean is a method-level annotation. When JavaConfig encounters a method with annotated with @Bean, it will execute that method and register the return value as a bean within a BeanFactory. By default, the bean name (I.e, Bean ID) will be the same as the method name. Therefore a bean is registered with the method name as the bean ID.

The below simple example show usage of @Bean and @Configuration annotations.

@Configuration
public class Application {

@Bean
public CustomerService customerService() {
return new CustomerService();
}

@Bean
public OrderService orderService() {
return new OrderService();
}
}

The preceding configuration is exactly equivalent to the following Spring XML:

<beans>
<bean id="customerService" class="com.companyname.projectname.CustomerService"/>
<bean id="orderService" class="com.companyname.projectname.OrderService"/>
</beans>

@Import

There could be multiple java configuration classes. However, to bring dependencies from one configuration class to another we should use @Import annotation.

@Configuration
class DataBaseConfig{
@Bean
public DataBaseService databaseService(){
return new DataBaseServiceImpl();
}
}

@Configuration
@Import(DataBaseConfig.class)
public class AppConfig {

@Bean
public Controller controller(DataBaseService databaseService){
return new ControllerImpl(databaseService);
}
}

References

[1] https://docs.spring.io

[2] https://www.tutorialspoint.com

[3] https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring

--

--