(Reference: Spring Docs - Customizing Beans)
πΉ Why Customize Beans?
π‘ Spring allows us to modify how beans behave using annotations and configurations.
π‘ Customization gives us control over bean instantiation, dependency resolution, and initialization.
π Key Customization Features
π₯ Spring provides several ways to customize beans:
1οΈβ£ Lazy vs. Eager Initialization (@Lazy
)
2οΈβ£ Defining Primary Beans (@Primary
)
3οΈβ£ Using Qualifiers for Specific Bean Selection (@Qualifier
)
4οΈβ£ Conditional Beans (@Conditional
)
1οΈβ£ Lazy vs. Eager Initialization (@Lazy
)
π₯ By default, Singleton Beans are created at startup.
π₯ With @Lazy
, Spring delays bean creation until it is actually needed.
π Example:
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy
public class Kraken {
public Kraken() {
System.out.println("π¦ Kraken is awakening lazily...");
}
}
Test with a REST Controller:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/lazy")
public class LazyController {
private final Kraken kraken;
public LazyController(Kraken kraken) {
this.kraken = kraken;
}
@GetMapping
public String awakenKraken() {
return "β Kraken is now awake!";
}
}
π‘ Bean is NOT created at startup! It is only created when /lazy
endpoint is called.
2οΈβ£ Defining Primary Beans (@Primary
)
π₯ If multiple beans of the same type exist, Spring needs to know which one to use by default.
π₯ @Primary
marks a bean as the default choice unless explicitly overridden.
π Example:
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
@Primary
public class MainCaptain implements Captain {
@Override
public String command() {
return "π΄ββ οΈ Main Captain: Full speed ahead!";
}
}
@Component
public class BackupCaptain implements Captain {
@Override
public String command() {
return "β Backup Captain: Ready if needed!";
}
}
π‘ When injecting Captain
, MainCaptain
is used by default.
3οΈβ£ Using Qualifiers for Specific Bean Selection (@Qualifier
)
π₯ When multiple beans exist, we can use @Qualifier
to specify which one to inject.
π Example:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class Ship {
private final Captain captain;
public Ship(@Qualifier("backupCaptain") Captain captain) {
this.captain = captain;
}
public String sail() {
return captain.command();
}
}
π‘ Now BackupCaptain
is explicitly used instead of MainCaptain
.
4οΈβ£ Conditional Beans (@Conditional
)
π₯ @Conditional
allows us to register beans based on runtime conditions.
π₯ Useful for feature toggles, environment-based configurations, or platform-specific beans.
π Example: Load a bean only if a certain property is set.
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
@Component
@Conditional(StormyWeatherCondition.class)
public class StormySail {
public StormySail() {
System.out.println("βοΈ Storm detected! Adjusting sails...");
}
}
π Custom Condition Class:
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class StormyWeatherCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "stormy".equals(context.getEnvironment().getProperty("weather.mode"));
}
}
π‘ If weather.mode=stormy
is set in application.properties
, StormySail
bean will be loaded.
π Hands-On Project: Testing Bean Customization
π‘ Letβs modify our Spring Boot app to test these customizations!
Step 1: Create a Spring Boot Project
1οΈβ£ Go to Spring Initializr
2οΈβ£ Select:
- Spring Boot Version: Latest stable
- Dependencies: Spring Web
- Packaging: Jar 3οΈβ£ Click Generate and extract the zip file.
Step 2: Define Beans with Custom Behavior
π Lazy Bean:
@Component
@Lazy
public class Kraken {
public Kraken() {
System.out.println("π¦ Kraken is awakening lazily...");
}
}
π Primary & Alternative Beans:
@Component
@Primary
public class MainCaptain implements Captain {
@Override
public String command() {
return "π΄ββ οΈ Main Captain: Full speed ahead!";
}
}
@Component
public class BackupCaptain implements Captain {
@Override
public String command() {
return "β Backup Captain: Ready if needed!";
}
}
π Conditional Bean:
@Component
@Conditional(StormyWeatherCondition.class)
public class StormySail {
public StormySail() {
System.out.println("βοΈ Storm detected! Adjusting sails...");
}
}
Step 3: Create a REST Controller to Test Beans
π Lazy Bean Activation:
@RestController
@RequestMapping("/lazy")
public class LazyController {
private final Kraken kraken;
public LazyController(Kraken kraken) {
this.kraken = kraken;
}
@GetMapping
public String awakenKraken() {
return "β Kraken is now awake!";
}
}
π Check which Captain is Injected:
@RestController
@RequestMapping("/captain")
public class CaptainController {
private final Captain captain;
public CaptainController(Captain captain) {
this.captain = captain;
}
@GetMapping
public String getCaptain() {
return captain.command();
}
}
Step 4: Run the Application & Test
π‘ Run the app using:
mvn spring-boot:run
or
./mvnw spring-boot:run
π Test Lazy Initialization:
- Open browser and visit:
http://localhost:8080/lazy
- You should see:
"β Kraken is now awake!"
- And in logs:
"π¦ Kraken is awakening lazily..."
π Test Default vs. Qualified Bean Injection:
- Open browser and visit:
http://localhost:8080/captain
- If
@Primary
is used β"π΄ββ οΈ Main Captain: Full speed ahead!"
- If
@Qualifier("backupCaptain")
is used β"β Backup Captain: Ready if needed!"
π Summary
β
@Lazy
delays bean creation until needed.
β
@Primary
sets the default bean when multiple exist.
β
@Qualifier
allows precise bean selection.
β
@Conditional
loads beans based on runtime conditions.
π Topics Covered in This Section
π Customizing Beans in Spring (βοΈ Covered)
- Lazy vs. Eager Initialization (@lazy).
- Setting Default Beans with @primary.
- Overriding with @Qualifier when multiple beans exist.
- Conditional Beans (@Conditional) for dynamic configurations.
π οΈ Spring Boot & Customization (βοΈ Covered)
- When to use lazy initialization for performance optimization.
- How @primary works in multi-bean scenarios.
- Using @Conditional to load beans based on environment properties.
π₯ Key Takeaways You Need to Remember:
β
@lazy prevents beans from being created at startup.
β
@primary sets the default bean when multiple exist.
β
@Qualifier ensures the correct bean is injected.
β
@Conditional allows runtime-based bean loading.
Top comments (0)