Instantiating Beans Through XML Configuration
Spring's IoC container manages bean lifecycle and dependencies via XML metadata. This section explores multiple instantiation strategies and configuration attributes.
Core Bean Tag Attributes
- id: Unique bean identifier (required). Must be alphanumeric without special characters.
- class: Fully qualified class name of the bean implementation.
- name: Alternative to id, allows special characters like slashes or spaces.
- scope: Defines bean lifecycle:
singleton: Single shared instance (default)prototype: New instance per request
Constructor-Based Instantiation (No-Argument)
The most common approach relies on a default constructor:
// Model class
package com.example.model;
public class Device {
public void displayDetails() {
System.out.println("Device instance created...");
}
}
<!-- spring-config.xml -->
<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="gadget" class="com.example.model.Device"/>
</beans>
// Test harness
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DeviceTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
Device gadget = (Device) ctx.getBean("gadget");
gadget.displayDetails();
}
}
Note: Java provides implicit no-arg constructors unless overridden. Explicitly declare one when using parameterized constructors.
Static Factory Method Pattern
Delegate instantiation to a static method:
// Static factory
package com.example.factory;
import com.example.model.Device;
public class StaticDeviceFactory {
public static Device createDevice() {
return new Device();
}
}
<bean id="staticGadget" class="com.example.factory.StaticDeviceFactory"
factory-method="createDevice"/>
Instance Factory Method Pattern
Requires factory instance before creating target beans:
// Instance factory
package com.example.factory;
import com.example.model.Device;
public class InstanceDeviceFactory {
public Device buildDevice() {
return new Device();
}
}
<!-- Factory bean must exist first -->
<bean id="deviceFactory" class="com.example.factory.InstanceDeviceFactory"/>
<bean id="instanceGadget" factory-bean="deviceFactory" factory-method="buildDevice"/>
Dependecny Injection Techniques
Constructor Argument Injection
Inject values during object construction:
// Modified Device class
public class Device {
private String brand;
public Device() {}
public Device(String brand) {
this.brand = brand;
}
public void displayDetails() {
System.out.println(brand + " device initialized...");
}
}
<bean id="brandedDevice" class="com.example.model.Device">
<constructor-arg name="brand" value="TechPro"/>
</bean>
Setter-Based Property Injection
More flexible approach using setters:
public class Device {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
public void displayDetails() {
System.out.println(brand + " device configured...");
}
}
<bean id="configuredDevice" class="com.example.model.Device">
<property name="brand" value="SmartTech"/>
</bean>
Injceting Object Dependencies
Wire beans together using references:
// Dependent class
public class UserProfile {
private String username;
private String role;
// Getters and setters omitted for brevity
public void setUsername(String username) { this.username = username; }
public void setRole(String role) { this.role = role; }
public String getUsername() { return username; }
public String getRole() { return role; }
}
// Device with dependency
public class Device {
private String brand;
private UserProfile owner;
public void setBrand(String brand) { this.brand = brand; }
public void setOwner(UserProfile owner) { this.owner = owner; }
public void displayDetails() {
System.out.println(brand + " owned by " + owner.getUsername() + " (" + owner.getRole() + ")");
}
}
<bean id="adminProfile" class="com.example.model.UserProfile" scope="prototype">
<property name="username" value="admin"/>
<property name="role" value="Administrator"/>
</bean>
<bean id="ownedDevice" class="com.example.model.Device">
<property name="brand" value="UltraBook"/>
<property name="owner" ref="adminProfile"/>
</bean>
Injecting Complex Data Structures
Configure arrays, lists, and maps:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Device {
private String[] supportedBrands;
private List<Integer> ports;
private Map<String, String> specifications;
// Setters omitted
public void setSupportedBrands(String[] brands) { this.supportedBrands = brands; }
public void setPorts(List<Integer> ports) { this.ports = ports; }
public void setSpecifications(Map<String, String> specs) { this.specifications = specs; }
public void displayDetails() {
System.out.println("Brands: " + Arrays.toString(supportedBrands));
System.out.println("Ports: " + ports);
System.out.println("Specs: " + specifications);
}
}
<bean id="complexDevice" class="com.example.model.Device">
<!-- Array injection -->
<property name="supportedBrands">
<list>
<value>Acer</value>
<value>Asus</value>
<value>Dell</value>
</list>
</property>
<!-- List injection -->
<property name="ports">
<list>
<value>8080</value>
<value>3306</value>
<value>5432</value>
</list>
</property>
<!-- Map injection -->
<property name="specifications">
<map>
<entry key="cpu" value="i7"/>
<entry key="ram" value="16GB"/>
<entry key="storage" value="512GB SSD"/>
</map>
</property>
</bean>