If-else Optimization of Bean Autowiring
Li Wei
Title: Optimizing If‑else with Bean Autowiring
Introduction
In the Spring framework we often encounter code like this:
@Resource
private Map<String, ConditionHandler> conditionHandlerMap;
The line looks simple, but it hides the powerful mechanisms of the Spring IoC container. This article delves into how Spring automatically injects all implementations of ConditionHandler into this map.
Background
Business scenario:
Suppose we have a conditional‑evaluation system that needs to support various operators: equals, greaterThan, lessThan, etc. A traditional approach might look like this:
if (op.equals("equals")) { … }
else if (op.equals("greaterThan")) { … }
else if (op.equals("lessThan")) { … }
Optimized solution:
Use the Strategy pattern together with Spring dependency injection:
@Resource
private Map<String, ConditionHandler> conditionHandlerMap;
Core question: How does Spring know which beans to put into this map?
Core Interface Design
Strategy interface:
public interface ConditionHandler {
boolean handle(Object left, Object right);
}
Concrete strategy implementations:
@Component
public class Equals implements ConditionHandler { … }
@Component
public class GreaterThan implements ConditionHandler { … }
@Component
public class LessThan implements ConditionHandler { … }
Spring Container Startup Process
Phase 1: Component scanning
Scanning results:
Equalsclass is annotated with@ComponentGreaterThanclass is annotated with@ComponentLessThanclass is annotated with@Component- …
Phase 2: Bean definition registration
Bean‑name generation rules:
Equals→equals(class name with the first letter lower‑cased)GreaterThan→greaterThanLessThan→lessThan
Registration result:
BeanDefinition for equals → class Equals
BeanDefinition for greaterThan → class GreaterThan
BeanDefinition for lessThan → class LessThan
Dependency‑Injection Trigger Mechanism
When Spring creates an instance of RouteLabelConditionProcessor, the internal flow is:
- Instantiate
RouteLabelConditionProcessor - Scan all fields of the class and find the
@Resourceannotation - Resolve the field type:
Map<String, ConditionHandler> - Trigger the dependency‑injection logic
Dependency descriptor:
Field: conditionHandlerMap
Type: java.util.Map<java.lang.String, com.example.ConditionHandler>
Annotation: @Resource
Core Algorithm for Map Dependency Resolution
Finding candidate beans:
Spring looks for all beans whose type matches ConditionHandler.
Type‑matching process:
- Examine the generic type of the map (
ConditionHandler). - Collect every bean that implements this interface.
Matching example:
Equals→ matchesGreaterThan→ matchesLessThan→ matches
Final map assembly:
After the above steps, Spring builds a map like:
{
"equals" : equalsBean,
"greaterThan": greaterThanBean,
"lessThan" : lessThanBean
}
Runtime Usage
Strategy selection:
ConditionHandler handler = conditionHandlerMap.get(operator);
boolean result = handler.handle(left, right);
Performance advantages:
- Map lookup: O(1) time complexity
- Avoids if‑else: No matter how many operators exist, lookup time stays constant
- Type safety: Compile‑time guarantees correct types
FAQ
Q1: What happens if two implementation classes have the same name?
A: Spring throws a BeanDefinitionStoreException because of a bean‑name conflict.
Q2: Can I customize the bean name?
A: Yes, specify a name with @Component("customName").
Q3: Must the map’s key be the bean name?
A: Yes, by default Spring uses the bean name as the map key.
Q4: What if no implementation classes are found?
A: If the field is annotated with @Resource(required=true) (the default), Spring throws a NoSuchBeanDefinitionException.
Summary
Spring’s map‑dependency‑injection mechanism works through the following steps:
- Scanning phase: Detect all classes annotated with
@Component. - Registration phase: Register each class as a
BeanDefinition. - Resolution phase: Analyze the generic information of the
Map. - Matching phase: Find all beans that implement the
ConditionHandlerinterface. - Assembly phase: Build the
Map<String, ConditionHandler>. - Injection phase: Inject the map into the target field.
This mechanism dramatically improves code maintainability and extensibility, showcasing the elegance of Spring’s design.
Originally written by Li Wei (李唯_) and published in Chinese on 后端技术栈全书 (Full-Stack Backend Engineering). Translated and adapted for DriftSeas with permission.