Managing Beans in the Spring Framework
Bean Configuration Methods
1. XML-Based Configuration
This is a foundational approach where bean definitions, properties, and dependencies are declared within an XML configuration file. It allows for detailed specification of bean metadata such as class name, identifier, scope, lazy initialization, and lifecycle methods (init and destroy). Dependency injection via property setters or constructors is also configured here.
2. Java-Based Configuration
Introduced in Spring 3.0, this method uses Java classes as configuration sources. Key annotations include @Configuration to mark a configuration class, @Bean to define a bean within such a class, and @ComponentScan to enable component scanning in specified packagess.
3. Annotation-Based Configuration
Dependencies are configured directly within Java classes using annotations, reducing reliance on XML. Common annotations for automatic dependency injection include @Autowired, @Resource, and @Qualifier.
4. Factory Method Configuration
Beans can be instantiated via factory methods, which are categorized as static or instance methods. The static factory method encapsulates object creation logic within a static method. In Spring XML, a bean created this way is declared by specifying the class containing the factory method and the method's name.
Bean Scope
The scope of a bean, defined by the scope attribute in the <bean> element or corresponding annotations, determines the lifecycle and visibility of the bean instance.
| Scope | Description |
|---|---|
| singleton | Default. A single shared instance per Spring IoC container. |
| prototype | A new instance is created each time the bean is requested. |
| request | In web applications, a new instance per HTTP request. |
| session | In web applications, a single instance per HTTP session. |
| application | In web applications, a single instance per ServletContext. |
| websocket | In web applications, a single instance per WebSocket session. |
Singleton vs. Prototype Scope
Singleton (scope="singleton"):
- Instance Count: One per container.
- Instantiation Timing: When the application context is loaded.
- Lifecycle:
- Creation: On container startup.
- Lifetime: Lives as long as the container is active.
- Destruction: When the container is shut down.
Prototype (scope="prototype"):
- Instance Count: Multiple; a new instance for each request.
- Instantiation Timing: When
getBean()is called. - Lifecycle:
- Creation: When the bean is requested.
- Lifetime: Managed by the client code after creation.
- Destruction: The Spring container does not manage the complete lifecycle of prototype beans. Destruction is typically handled by the Java garbage collector.
Configuring Bean Lifecycle Methods
Custom initialization and destruction logic can be specified for a bean.
init-method: Specifies the name of a method in the bean class to be called after properties are set. This method performs custom initialization.destroy-method: Specifies the name of a method to be called just before the bean is destroyed by the container, allowing for resource cleanup.
<bean id="exampleBean" class="com.example.ExampleService"
init-method="initialize"
destroy-method="cleanup" />
public class ExampleService {
public void initialize() {
// Initialization logic
}
public void cleanup() {
// Cleanup logic
}
}
Overview of Spring Bean Loading Process
The bean loading process involves two primary phases:
- Parsing and Registration: Spring parses configuration sources (XML, annotations). It reads class metadata and creates corresponding
BeanDefinitionobjects, which are registered with theBeanFactory. - Instantiation and Population: Based on the
BeanDefinition, the container instantiates beans, populates their properties (dependency injection), and applies post-processors. Singleton beans are then cached, typically in a map namedsingletonObjects.
Dependency Injection Property Configuration
1. Two Primary Injection Styles
1.1 Setter Injection
Dependencies are injected via setter methods. The Spring container calls these setters after instantiating the bean.
public class OrderProcessor {
private PaymentGateway paymentGateway;
// Setter for dependency injection
public void setPaymentGateway(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
<bean id="paymentGateway" class="com.example.StripeGateway" />
<bean id="orderProcessor" class="com.example.OrderProcessor">
<property name="paymentGateway" ref="paymentGateway" />
</bean>
1.2 Using the P-Namespace
A shorthand for setter injection in XML, using the p: namespace.
- Declare the namespace in the
<beans>root element:xmlns:p="http://www.springframework.org/schema/p" - Use it for injection:
<bean id="petDog" class="com.example.Dog"> <property name="name" value="Rex" /> </bean> <bean id="owner" class="com.example.Person" p:firstName="Alice" p:dog-ref="petDog" />
1.3 Constructor Injection
Dependencies are provided as arguments to the bean's constructor, ensuring the bean is fully initialized upon creation.
public class OrderProcessor {
private final PaymentGateway paymentGateway;
private final InventoryService inventoryService;
// Constructor for dependency injection
public OrderProcessor(PaymentGateway pg, InventoryService is) {
this.paymentGateway = pg;
this.inventoryService = is;
}
}
<bean id="paymentGateway" class="com.example.StripeGateway" />
<bean id="inventoryService" class="com.example.InventoryServiceImpl" />
<bean id="orderProcessor" class="com.example.OrderProcessor">
<constructor-arg ref="paymentGateway" />
<constructor-arg ref="inventoryService" />
</bean>
2. Injecting Collection Properties
Spring supports injecting values into collection-typed properties (List, Set, Map, Properties). This is often used for configuration parameters.
<bean id="systemConfig" class="com.example.AppConfiguration">
<!-- Injecting a List -->
<property name="serverList">
<list>
<value>server1.example.com</value>
<value>server2.example.com</value>
<ref bean="primaryServer" />
</list>
</property>
<!-- Injecting a Set -->
<property name="adminRoles">
<set>
<value>ROLE_SUPER_ADMIN</value>
<value>ROLE_ADMIN</value>
</set>
</property>
<!-- Injecting a Map -->
<property name="connectionSettings">
<map>
<entry key="timeout" value="5000" />
<entry key="retries" value="3" />
<entry key="defaultHost" value-ref="defaultServer" />
</map>
</property>
<!-- Injecting a java.util.Properties -->
<property name="appProperties">
<props>
<prop key="app.version">2.1.0</prop>
<prop key="app.mode">production</prop>
</props>
</property>
</bean>
public class AppConfiguration {
private List<Object> serverList;
private Set<String> adminRoles;
private Map<String, Object> connectionSettings;
private Properties appProperties;
// Corresponding setters omitted for brevity
}