Spring Core Container Configuration and Dependency Injection

Spring Core Container Architecture

The Spring framework is composed of several modules, including Core Container, Data Access, Web, and Testing. The Core Container serves as the foundation, providing the Inversion of Control (IoC) and Dependency Injection (DI) features. It is crucial to distinguish between BeanFactory and ApplicationContext, the two primary interfaces for container management.

  • BeanFactory: This is the root interface for accessing the Spring container. It implements lazy loading, meaning beans are instantiated only when requested via the getBean() method.
  • ApplicationContext: This extends BeanFactory and is the preferred interface for enterprise applications. It employs eager loading by default, pre-instantiating all singleton beans upon startup.

For singleton beans, immediate loading is preferred to detect configuration errors early. For prototype beans, which are stateful, lazy loading is more appropriate to conserve resources.

Bean Creation Strategies

Spring supports three primary methods for instantiating beans within the IoC container:

1. Constructor Instantiation

The default method uses the class's no-argument constructor. If a bean definition lacks specific factory methods, Spring relies on reflection to call the default constructor.

<bean id="userService" class="com.example.service.UserService"/>

2. Instance Factory Method

This approach uses a non-static method of an existing factory bean to create the target object.

<bean id="serviceFactory" class="com.example.factory.ServiceFactory"/>
<bean id="userService" factory-bean="serviceFactory" factory-method="createUserService"/>

3. Static Factory Method

This involves a static method within a factory class to instantiate the bean.

<bean id="userService" class="com.example.factory.StaticServiceFactory" factory-method="newInstance"/>

Bean Scopes and Lifecycle

The scope of a bean determines the lifecycle and visibility of the object instance.

ScopeDescription
singletonDefault. A single instance per IoC container.
prototypeA new instance is created every time the bean is requested.
requestA single instance per HTTP request (Web context).
sessionA single instance per HTTP session (Web context).
applicationA single instance per ServletContext (Web context).

Lifecycle Callbacks

For singleton beans, the lifecycle is tied to the container: they are created on startup and destroyed on shutdown. Prototype beans are created on demand, and the container delegates their lifecycle management to the client code (Garbage Collector).

You can define initialization and destruction callbacks using XML attributes or annotations.

<bean id="dataSource" class="com.example.DataSource" 
      init-method="init" destroy-method="cleanup" scope="singleton"/>

Dependency Injection Mechanisms

Dependency Injection (DI) separates the creation of dependencies from the business logic. There are three main data types to inject: primitives/Strings, other beans, and collections.

Constructor Injection

Dependencies are passed via the constructor. This ensures the object is never in an invalid state.

public class OrderProcessor {
    private final PaymentService paymentService;

    public OrderProcessor(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}
<bean id="orderProcessor" class="com.example.OrderProcessor">
    <constructor-arg ref="paymentService"/>
</bean>

Setter Injection

Dependencies are injected via setter methods. This is more flexible and commonly used for optional dependencies.

<bean id="orderProcessor" class="com.example.OrderProcessor">
    <property name="paymentService" ref="paymentService"/>
</bean>

Collection Injection

XML configuration allows injecting Lists, Sets, Maps, and Properties.

<bean id="configHolder" class="com.example.ConfigHolder">
    <property name="allowedTypes">
        <list>
            <value>ADMIN</value>
            <value>USER</value>
        </list>
    </property>
    <property name="configMap">
        <map>
            <entry key="timeout" value="5000"/>
        </map>
    </property>
</bean>

Annotation-Based Configuration

Modern Spring development favors annotations over XML for cleaner code.

Component Registration

Stereotype annotations mark classes for automatic detection via classpath scanning.

  • @Component: Generic stereotype.
  • @Service: Service layer.
  • @Repository: Data access layer.
  • @Controller: Presentation layer.

To enable scanning, add <context:component-scan> to XML or use @ComponentScan in Java config.

Dependency Injection Annotations

  • @Autowired: Injects by type. If multiple candidates exist, a NoUniqueBeanDefinitionException is thrown.
  • @Qualifier: Used with @Autowired to specify a bean name when multiple candidates exist.
  • @Resource: JSR-250 standard. Injects by name by default.
  • @Value: Injects primitive values or properties from files.

Scope and Lifecycle Annotations

  • @Scope("prototype"): Defines the scope.
  • @PostConstruct: Marks the initialization method.
  • @PreDestroy: Marks the destruction method.

Java-Based Container Configuration

You can replace XML entirely with Java configuration classes.

  • @Configuration: Indicates the class is a source of bean definitions.
  • @ComponentScan: Configures component scanning.
  • @Bean: Marks a method that returns a bean to be managed by the container.
  • @Import: Imports other configuration classes.
  • @PropertySource: Loads properties files.

Configuration Example

@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:application.properties")
public class AppConfig {

    @Value("${db.url}")
    private String dbUrl;

    @Bean
    @Scope("prototype")
    public DataSource dataSource() {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setJdbcUrl(dbUrl);
        return ds;
    }
}

Integration Testing

Spring provides integration with JUnit to simplify testing. The SpringJUnit4ClassRunner creates an ApplicationContext for the test duration, eliminating repetitive setup code.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class ServiceIntegrationTest {

    @Autowired
    private UserService userService;

    @Test
    public void testUserCreation() {
        assertNotNull(userService.findById(1L));
    }
}

Spring vs. Spring Boot

Spring Boot is an extension of the Spring framework. It emphasizes "convention over configuration" to minimize XML setup. While Spring requires manual configuration of dependencies (e.g., data sources, MVC), Spring Boot provides auto-configuration that sets up sensible defaults based on classpath dependencies, enabling rapid application development.

Tags: Spring Framework IoC Container Dependency Injection Java Configuration Spring Beans

Posted on Fri, 17 Jul 2026 17:14:46 +0000 by Rohan Hill