Where do I put my XML beans in a Spring Boot application?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Spring Boot favors Java-based configuration and component scanning, but many teams still maintain XML bean definitions for legacy modules or third-party integration. The key question is not only where to place XML files, but how to load them predictably across local runs, tests, and packaged deployments.
In most cases, XML bean files belong in src/main/resources so they are available on the classpath at runtime. Then import them explicitly into Boot configuration with @ImportResource or context configuration properties.
Core Sections
1. Place XML under classpath resources
A common structure:
src/main/resources/spring/legacy-beans.xmlsrc/main/resources/spring/integration.xml
This ensures files are bundled in JAR/WAR and accessible via classpath regardless of filesystem layout.
2. Import XML using @ImportResource
This is the most direct method and keeps XML loading explicit in code.
3. Split configuration by profile when needed
If some XML beans are environment-specific, use profile-specific imports in Java config or conditionally activate bean sets. Avoid loading all XML files globally when only one environment requires them.
4. Verify bean registration and conflicts
XML beans can conflict with component-scanned beans by name or type. Add tests to confirm expected wiring:
If duplicate beans exist, use explicit bean names or @Primary where appropriate.
5. Gradual migration from XML to Java config
For long-term maintainability, migrate XML beans incrementally to Java configuration classes. Keep integration tests to ensure behavior remains unchanged during migration.
Common Pitfalls
- Storing XML outside classpath resources and relying on fragile filesystem-relative paths.
- Forgetting to import XML files, leading to missing bean definitions at runtime.
- Loading all legacy XML indiscriminately and introducing unnecessary bean conflicts.
- Mixing XML and annotation configs without clear ownership of bean names.
- Migrating away from XML without regression tests for context wiring behavior.
Summary
In Spring Boot, XML beans should typically live in src/main/resources and be loaded explicitly with @ImportResource. Keep loading profile-aware when appropriate, validate context wiring in tests, and manage bean naming conflicts carefully. If XML is legacy debt, migrate gradually to Java config with parity checks. This approach keeps Boot startup predictable while supporting practical transition paths for older Spring modules.
To make this guidance robust in day-to-day engineering work, treat it as an executable checklist instead of one-time reading material. Capture the expected environment, dependency versions, runtime flags, and validation commands in your repository so every contributor can reproduce the same behavior from a clean setup. This is especially important when onboarding new developers, rotating on-call ownership, or debugging incidents under time pressure. Documentation that includes concrete commands, expected outputs, and failure interpretation prevents repeat confusion and shortens recovery time.
It is also worth adding at least one automated guardrail in CI that validates the highest-risk assumption described in the article. Depending on the topic, that guardrail may be a smoke test, policy check, schema validation, benchmark threshold, import check, or integration assertion against a minimal fixture. The goal is to fail fast when environment drift or configuration changes reintroduce old errors. Teams that convert troubleshooting knowledge into small, repeatable checks reduce operational noise and keep this class of issue from returning every sprint.
As a final hardening step, schedule a periodic verification run that executes the documented checks in a fresh environment image. This catches slow drift in platform defaults, dependency transitive updates, and infrastructure policies that may otherwise remain invisible until production rollout.

