Spring Framework Fundamentals: An Overview of Core Concepts and Lifecycle
Introduction to Spring Core Concepts
Before diving into the Spring framework, it's essential to understand its fundamental building blocks. These include:
- Inversion of Control (IoC) and Dependency Injection (DI)
- Aspect-Oriented Programming (AOP)
- Bean lifecycle and initialization
- Transaction management
Let's begin with a simple "Hello World" example to illustrate the basic usage of Spring's core container.
A Simple "Hello World" Example
Spring can be configured in two primary ways: XML-based configuration and annotation-based configuration. Both approaches achieve the same goal of defining and managing application components (beans).
XML Configuration
The traditional approach involves defining beans in an XML file. The application context is then loaded from this XML file.
// Load the Spring context from an XML configuration file
ApplicationContext appContext = new ClassPathXmlApplicationContext("application-context.xml");
// Retrieve a bean by its name
UserService userSvc = appContext.getBean("userService", UserService.class);
// Execute a method on the bean
userSvc.performAction();
The corresponding application-context.xml file would look like this:
<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">
<!-- Scan for components in a specified package -->
<context:component-scan base-package="com.example.spring"/>
<!-- Define a bean manually -->
<bean id="userService" class="com.example.spring.service.UserService"/>
</beans>
Annotation-Based Configuration
A more modern approach uses Java-based configuration classes annotated with Spring's stereotype annotations.
// Load the Spring context from a Java configuration class
ApplicationContext appContext = new AnnotationConfigApplicationContext(SpringConfig.class);
// Retrieve a bean by its name or type
UserService userSvc = appContext.getBean("userService", UserService.class);
// Execute a method on the bean
userSvc.performAction();
The configuration class is defined as follows:
@Configuration
@ComponentScan("com.example.spring")
public class SpringConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
The Bean Creation Process
When a bean is requested, Spring follows a specific lifecycle to create and initialize it. The general steps are:
- Instantiation: The bean is created using its constructor.
- Dependency Injection: Spring populates the bean's properties. If a property is annotated with
@Autowired, Spring injects the corresponding dependency from its container. - Aware Callbacks: If the bean implements any
Awareinterfaces (e.g.,BeanFactoryAware,ApplicationContextAware), the relevant callback methods are invoked. - Initialization: If the bean implements the
InitializingBeaninterface, itsafterPropertiesSet()method is called. Additionally, any method annotated with@PostConstructis executed. - AOP Proxying: If the bean is configured for Aspect-Oriented Programming, Spring creates a proxy object. This proxy intercepts method calls to apply cross-cutting concerns like logging or security.
After creation, the bean's scope determines its lifecycle:
- Singleton (default): The bean is stored in a singleton cache. Subsequent requests for the same bean return the cached instance.
- Prototype: A new instance is created every time the bean is requested. Its not stored in the cache.
Constructor Resolution
When a class has multiple constructors, Spring applies a specific strategy to choose one:
- If there is only one constructor, it is used.
- If there are multiple constructors, Spring prefers a no-argument constructor.
- If a constructer is annotated with
@Autowired, it is used. Spring resolves its parameters by type, and if multiple matches exist, by name.
Aspect-Oriented Programming (AOP) Flow
AOP allows you to modularize cross-cutting concerns. The process involves:
- Spring scans for classes annotated with
@Aspectduring startup. - It identifies methods within these aspects that are annotated with advice types like
@Before,@After, or@Around. - For each target bean, Spring evaluates if any of its methods match the pointcut expressions defined in the aspects.
- If a match is found, Spring creates a proxy for the target bean. This proxy intercepts method calls and delegates them to the aspect's advice logic before or after executing the target method.
Transaction Management
The @Transactional annotation is a key feature for managing database transactions. Its workflow is:
- When a bean method is annotated with
@Transactional, Spring creates a proxy for that bean. - Upon invocation of the method, the proxy uses a
TransactionManagerto obtain a database connection. - The connection's auto-commit mode is disabled.
- The business logic method is executed.
- If the method completes without exceptions, the transaction is committed. If an exception occurs, the transaction is rolled back.