Dependency Injection (DI) → decouples the application objects from each other
Construction and method level injection
Inversion of Control (IoC) container manages creating objects → decoupling objects management from the application
Aspect Oriented Programming (AOP) → decouple cross-cutting concerns from the objects that they affect
Examples of aspects: logging, declarative transactions, security, caching, etc.
Spring framework offers about 20 modules.
We can pick and choose only the modules that are needed without having to bring in the rest.
The Core module provides the fundamental parts of the framework, including the IoC and Dependency Injection features.
The Bean module provides BeanFactory, which is a sophisticated implementation of the factory pattern.
The Context module builds on the solid base provided by the Core and Beans modules and it is a medium to access any objects defined and configured. The ApplicationContext interface is the focal point of the Context module.
The SpEL module provides a powerful expression language for querying and manipulating an object graph at runtime.
package com.test;
public class Car {
private String make;
public void setMake(String name){
this.make = make;
}
public String getMake(){
return make;
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Car obj = (Car) context.getBean("Car");
obj.getMake();
}
}
Beans.xml
<?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 = "mycar" class = "com.test.Car">
<property name = "make" value = "Bob"/>
</bean>
</beans>
Spring provides two types of containers:
BeanFactory Container: the simplest container providing the basic support for DI and is defined by the org.springframework.beans.factory.BeanFactory interface.
ApplicationContext Container: this container adds more enterprise-specific functionality such as the ability to resolve textual messages from a properties file and the ability to publish application events to interested event listeners. This container is defined by the org.springframework.context.ApplicationContext interface.
The ApplicationContext container includes all functionality of the BeanFactory container, so it is generally recommended over BeanFactory. BeanFactory can still be used for lightweight applications like mobile devices or applet-based applications where data volume and speed is significant.
How to create a bean
Bean's lifecycle details
Bean's dependencies
class: a mandatory attribute and specifies the bean class to be used to create the bean
name/id: the bean unique identifier; iIn XML based configuration metadata, id and/or name attributes to specify the bean identifier(s)
scope: the scope of the objects created
constructor-arg: to inject the dependencies
properties: to inject the dependencies
autowiring mode: to inject the dependencies
lazy-initialization mode: tells the IoC container to create a bean instance when it is first requested, rather than at the startup
initialization method: a callback to be called just after all necessary properties on the bean have been set by the container
destruction method: a callback to be used when the container containing the bean is destroyed
XML based configuration file.
Annotation-based configuration.
Java-based configuration.
singleton: a single instance per Spring IoC container (default).
prototype: any number of object instances.
request: HTTP request; only valid in the context of a web-aware Spring ApplicationContext.
session: HTTP session; only valid in the context of a web-aware Spring ApplicationContext.
global-session: global HTTP session; only valid in the context of a web-aware Spring ApplicationContext.
Example:
<bean id = "..." class = "..." scope = "prototype">
</bean>
Either implements InitializingBean (for initialization), DisposableBean (for destroy), or use XML based configuration metadata:
<bean id = "mycar" class = "com.test.Car" init-method = "init" destroy-method = "destroy" />
Default initialization and destroy methods: to avoid configuring them in every beans (if they use the same method names)
<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"
default-init-method = "init"
default-destroy-method = "destroy">
<bean id = "..." class = "...">
</bean>
</beans>
It has nothing to do with Java class inheritance but the inheritance concept is same.
Child beans can inherit the configuration from the parent bean.
<bean id = "myvehicle" class = "com.test.Vehicle">
<property name = "type" value = "Auto"/>
<property name = "..." value = "..."/>
</bean>
<bean id ="mycar" class = "com.test.Car" parent = "myvehicle">
<property name = "make" value = "Ford"/>
</bean>
Set abstract = true, and don't specify class attribute
<bean id = "beanTeamplate" abstract = "true">
<property name = "..." value = "..."/>
<property name = "..." value = "..."/>
</bean>
<bean id ="mycar" class = "com.test.Car" parent = "beanTeamplate">
<property name = "make" value = "Ford"/>
</bean>
Dependency Injection Type:
Constructor-based dependency injection
Setter-based dependency injection
👉 A good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies.
Example 1:
<bean id = "mycar" class = "com.test.Car">
<constructor-arg ref = "myengine"/>
</bean>
<bean id = "myengine" class = "com.test.Engine"></bean>
Example 2:
<bean id = "mycar" class = "com.test.Car">
<constructor-arg type = "int" value = "2001"/>
<constructor-arg type = "java.lang.String" value = "Ford"/>
</bean>
Example:
<bean id = "mycar" class = "com.test.Car">
<property name = "engine" ref = "myengine"/>
<property name = "year" value = "2001"/>
</bean>
<bean id = "myengine" class = "com.test.Engine"></bean>
Injecting null values:
<bean id = "..." class = "...">
<property name = "email"><null/></property>
</bean>
Inner beans (similar to inner class in Java) are defined within the scope of another bean. Thus, a <bean/> element inside the <property/> or <constructor-arg/>.
Example:
<bean id = "mycar" class = "com.test.Car">
<property name = "engine" ref = "myengine"/>
<bean id = "myengine = "com.test.Engine"/>
</property>
</bean>
Spring offers four types of collection configuration elements:
<list>: a list of values, allowing duplicates.
<set>: a set of values but without any duplicates.
<map>: a collection of name-value pairs where name and value can be of any type.
<props>: a collection of name-value pairs where the name and value are both Strings.
👉 Use either <list> or <set> to wire any implementation of java.util.Collection or an array.
Example 1:
<bean id = "myCarFactory" class = "com.test.CarFactory">
<!-- results in a setCarList(java.util.List) call -->
<property name = "carList">
<list>
<value>Ford</value>
<value>BMW</value>
<value>Honda</value>
<value>Toyota</value>
</list>
</property>
<!-- results in a setCarSet(java.util.Set) call -->
<property name = "carSet">
<set>
<value>Ford</value>
<value>BMW</value>
<value>Honda</value>
<value>Toyota</value>
</set>
</property>
<!-- results in a setCarMap(java.util.Map) call -->
<property name = "carMap">
<map>
<entry key = "1" value = "Ford"/>
<entry key = "2" value = "BMW"/>
<entry key = "3" value = "Honda"/>
<entry key = "4" value = "Toyata"/>
</map>
</property>
<!-- results in a setCarProp(java.util.Properties) call -->
<property name = "carProp">
<props>
<prop key = "one">Ford</prop>
<prop key = "two">BMW</prop>
<prop key = "three">Honda</prop>
<prop key = "four">Toyota</prop>
</props>
</property>
</bean>
Example 2: Injecting Bean References to Collections
<bean id = "..." class = "...">
<!-- Passing bean reference for java.util.List -->
<property name = "carList">
<list>
<ref bean = "bmw"/>
<ref bean = "ford"/>
<value>Honda</value>
</list>
</property>
<!-- Passing bean reference for java.util.Map -->
<property name = "carMap">
<map>
<entry key = "one" value = "Ford"/>
<entry key = "two" value-ref = "honda"/>
<entry key = "three" value-ref = "bmw"/>
</map>
</property>
</bean>
⚙ Component Scanning Approach (auto-detection)
Spring automatically detect and manage your beans based on classpath scanning.
@Component, @Service, @Repository, @Controller, @Autowired, @Qualifier, @Primary
Most common for application code
⚙ Java-based Configuration Approach (explicit bean detection)
Define beans manually in a @Configuration class using @Bean methods.
Often used for library classes, third-party beans, or fine-grained control
Autowiring modes:
byType: Matches bean by type (class or interface). If there’s exactly one bean of that type, it gets injected automatically.
byName: Matches bean by name (the property name equals the bean name). If multiple beans of the same type exist, it chooses one whose name matches the property.
constructor: Uses the constructor parameters to find matching beans. Similar to byType, but applies to constructor injection.
Define @component & Id:
// Engine interface
public interface Engine {
void start();
}
// Implementation 1
@Component("petrolEngine")
public class PetrolEngine implements Engine {
public void start() {
System.out.println("Petrol engine started.");
}
}
// Implementation 2
@Component("dieselEngine")
public class DieselEngine implements Engine {
public void start() {
System.out.println("Diesel engine started.");
}
}
Autowire by Type:
If there’s only one Engine bean:
@Component
public class Car {
@Autowired // Spring finds bean by type (Engine)
private Engine engine;
public void drive() {
engine.start();
}
}
But since we have two beans (PetrolEngine, DieselEngine), Spring will throw an error — ambiguity!
Autowire by Name:
If the field name matches a bean name, Spring uses that match:
@Component
public class Car {
@Autowired
private Engine petrolEngine; // matches bean name "petrolEngine"
public void drive() {
petrolEngine.start();
}
}
Spring injects the PetrolEngine bean because the field name matches the bean ID.
Explicit Choice With @Qualifier:
When multiple candidates exist, specify which one:
@Component
public class Car {
@Autowired
@Qualifier("dieselEngine") // specify which bean to inject
private Engine engine;
public void drive() {
engine.start();
}
}
Autowire by Constructor:
@Component
public class Car {
private final Engine engine;
@Autowired
public Car(@Qualifier("petrolEngine") Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start();
}
}
Behind the scenes, the Spring’s IoC container:
Scans for @Component classes.
Creates bean instances.
Checks for @Autowired annotations.
Matches and injects the right beans according to rules:
byType first,
then byName,
or uses @Qualifier if specified.
@Configuration is a class-level annotation.
It marks a class as a source of bean definitions for the Spring IoC container
It is type-safe replacement for XML configuration files.
@Bean is a method-level annotation used inside a @Configuration class.
The method defines, creates, and returns a Spring-managed bean.
The method name becomes the bean ID (by default), and the return type determines the bean’s type.
Example:
@Configuration
public class AppConfig {
@Bean
public Engine engine() {
return new PetrolEngine(); // this object becomes a bean
}
@Bean
public Car car() {
return new Car(engine()); // Spring injects engine() bean automatically
}
}
Behind the scenes, the Spring’s IoC container:
AppConfig is a configuration class (like an XML file).
engine() and car() define beans.
When the container starts:
Spring calls these methods,
Registers the returned objects as beans named engine and car.
Ensures dependencies (like engine() in car()) are resolved properly.