XML vs Java Config vs Annotations
Spring supports three configuration styles, and modern projects usually mix two of them.
Introduction
Spring supports three configuration styles, and modern projects usually mix two of them. Understanding the trade-offs lets you read any codebase fluently and pick the right tool for each part of your app.
The rule of thumb: annotations for your own classes, Java config for third-party objects you cannot annotate, XML only if you are maintaining a legacy module that already uses it.
Understanding the topic
The three styles side by side:
- XML — pure declaration in
applicationContext.xml. Verbose, decoupled from code, common in legacy systems. - Java config —
@Configurationclasses with@Beanmethods. Type-safe, refactor-friendly, fully programmable. - Annotations + scanning —
@Componentet al. discovered automatically. Concise for app code, opaque for third-party libraries.
Syntax reference
Same bean, three ways:
<!-- XML --><bean id="clock" class="java.time.Clock" factory-method="systemUTC"/>// Java config@Configurationclass TimeConfig {@Bean Clock clock() { return Clock.systemUTC(); }}// Annotation@Componentpublic class UtcClockProvider { /* ... */ }
Informative example
Conditional wiring with Java config — the kind of thing XML cannot express:
@Configurationclass CacheConfig {@BeanCache cache(@Value("${app.cache.kind:in-memory}") String kind) {return switch (kind) {case "redis" -> new RedisCache(/* host, port */);case "in-memory" -> new InMemoryCache(10_000);default -> throw new IllegalStateException("Unknown cache: " + kind);};}}
Java config gives you the full power of Java — conditions, loops, helper methods — which is why every modern Spring project uses it for non-trivial wiring.
Real-world use
Most codebases you join in 2026 are roughly 80% annotation-driven (your own classes), 15% Java config (third-party libraries, conditional wiring), and 5% XML (one legacy module nobody dares to touch). Knowing all three keeps you productive everywhere.
Best practices
- Use annotations for your own classes, Java config for third-party objects you can't annotate.
- Treat XML as read-only legacy; don't introduce it in new modules.
- Split Java config by concern (
SecurityConfig,WebConfig) instead of one mega-file.
Common mistakes
- Mixing two styles for the same bean — you end up with two instances and confusing behaviour.
- Putting business logic inside
@Beanmethods — they should construct and return, nothing more.
Hands-on exercise
Try this: wire a DataSource three different ways — XML, Java config, and annotation-based — in three branches of the same project. Run each and confirm the app behaves identically. Then delete the XML branch and never look back.