How to inject different services at runtime based on a property with Spring without XML
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
In Spring, selecting one service implementation based on configuration is a common requirement. The first thing to clarify is whether the choice happens once at application startup or repeatedly while the application is running. Without XML, the usual solutions are Java configuration, @ConditionalOnProperty, or a small factory that chooses among already-registered beans.
Startup-Time Selection with @ConditionalOnProperty
If the property value is fixed for the lifetime of the process, @ConditionalOnProperty is the cleanest solution. Spring creates only the matching bean during startup.
Start with an interface:
Two implementations:
Then wire the selected bean in a configuration class:
In application.yml:
Only one MessageSender bean will exist, so normal constructor injection works.
Consume the Selected Bean Normally
The service that depends on the selected implementation stays simple.
This is ideal for deployment-time configuration where the property is set once and stays stable.
True Runtime Selection with a Factory
If the implementation must change while the application is running, startup-only conditional wiring is not enough. In that case, register both implementations and select at call time through a factory or router.
Now a caller can select per invocation:
That is runtime selection because the property is consulted during method execution.
When @Primary and @Qualifier Are Enough
Not every injection problem requires property-based routing. Sometimes you simply need one default bean and one special-case bean.
Use:
- '
@Primarywhen one bean should be the default choice' - '
@Qualifierwhen a specific consumer should receive a specific bean' - '
@ConditionalOnPropertywhen configuration should decide startup wiring' - a factory when the choice must happen during application execution
Using the wrong mechanism usually makes the bean graph harder to understand.
Test the Wiring Explicitly
Property-driven wiring should have an explicit test.
Tests like this catch invalid property names and ambiguous bean registration early.
Common Pitfalls
One common mistake is calling startup-time bean selection "runtime" selection. If the application must switch implementations after boot, @ConditionalOnProperty is not enough.
Another mistake is keeping @Component on multiple implementations while also creating config-driven beans, which can produce duplicate candidates.
Developers also rely on raw string property values without validation. Invalid values should fail clearly.
Finally, some code uses qualifiers everywhere when a small factory would express the routing rule more directly.
Summary
- Use
@ConditionalOnPropertywhen configuration decides the implementation at startup. - Use a factory or router when the choice must happen during execution.
- Keep bean registration explicit and avoid mixing multiple selection mechanisms without a reason.
- Remove duplicate bean definitions when moving to config-based wiring.
- Add tests for property-driven wiring so configuration mistakes fail early.
Related reading
- How to invoke the super constructor in Python?
- How to make a Generic Type Cast function
- How to make a Java class that implements one interface with two generic types?
- How to make a Java Generic method static?
- How to inject environmental variables inside spring xml configuration?
- How to install a specific JDK on Mac OS X?
- How to perform async initalization of lazy injection
- How to print instances of a class using print?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.