Foundation · Understand
From XML Beans to Modern Spring Configuration
Define one object graph with XML, @Configuration and @Bean, and component scanning—and see how every style produces bean-definition metadata for the same container.
Primary source: Spring Framework 6.2 Reference: Bean Overview
Lesson 2 of 14
1d streakThe Architectural Question
Without the XML-to-Java history, @Bean and @Component look like unrelated magic instead of alternative ways to describe object recipes.
What this guide proves
- XML bean metadata
- Java configuration
- Component scanning
Configuration styles feed the same container
Spring configuration has changed shape, but its job has stayed stable: describe which objects the container should manage and how they depend on one another. XML, @Configuration classes, @Bean methods, and component scanning are metadata sources—not different containers.
| Configuration source | What it contributes | Good fit |
|---|---|---|
XML <bean> | Explicit BeanDefinition metadata loaded from a resource | Legacy systems and externally visible wiring |
@Bean method | A definition backed by a Java factory method | Third-party types and explicit construction |
| Component scanning | Definitions discovered from annotated application classes | Controllers, services, repositories, and adapters |
| Boot auto-configuration | Conditional definitions contributed by libraries | Safe framework defaults that back off when replaced |
XML made the object graph external and explicit
Early Spring applications commonly placed bean metadata in XML. The id named the recipe, the class selected the implementation, and constructor arguments or properties described dependencies. ClassPathXmlApplicationContext read the resource and populated the container.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="paymentGateway" class="example.StripePaymentGateway">
<constructor-arg value="${stripe.api-key}" />
</bean>
<bean id="checkoutService" class="example.CheckoutService">
<constructor-arg ref="paymentGateway" />
</bean>
</beans>try (var context =
new ClassPathXmlApplicationContext("application-context.xml")) {
CheckoutService service = context.getBean(CheckoutService.class);
service.checkout(order);
}Why interviewers still ask about XML
Java configuration made the same recipes type-safe
@Configuration marks a class as a source of bean definitions. Each @Bean method is the Java equivalent of an XML <bean> element: the method name is normally the bean name, the return type is the exposed type, parameters are dependencies, and the method body constructs the object.
@Configuration
class PaymentConfiguration {
@Bean
PaymentGateway paymentGateway(PaymentProperties properties) {
return new StripePaymentGateway(properties.apiKey());
}
@Bean
CheckoutService checkoutService(PaymentGateway gateway) {
return new CheckoutService(gateway);
}
}Architectural Boundary · Do Not Confuse
XML <bean id="checkoutService">
@Bean CheckoutService checkoutService(...)
Both register a recipe named checkoutService. They differ in authoring format and tooling, not in the fundamental container model.
Active Recall Checkpoint
Does calling an @Bean method always create a fresh Java object?
Hint: Consider who is invoking the method and the bean scope.
Show answer & explanation
Not when the container resolves the bean definition. For a singleton-scoped bean, the container returns the managed singleton. Direct calls and proxy behavior depend on whether the configuration class uses full or lite configuration semantics, so application code should request dependencies through injection.
Component scanning discovers application-owned definitions
Component scanning searches configured packages for stereotype annotations and registers a BeanDefinition for each candidate. @Component is the general stereotype; @Service, @Repository, and @Controller add architectural meaning and can enable specialized framework behavior.
@Service
final class CheckoutService {
private final PaymentGateway gateway;
CheckoutService(PaymentGateway gateway) {
this.gateway = gateway;
}
}Scanning does not create arbitrary objects
Trace every style into the BeanDefinition pipeline
- 01A metadata reader, configuration parser, or scanner discovers configuration.
- 02The container registers BeanDefinition recipes in a BeanDefinitionRegistry.
- 03BeanFactoryPostProcessor implementations may modify the recipes before ordinary beans exist.
- 04The BeanFactory instantiates beans and resolves dependencies from the registered definitions.
- 05BeanPostProcessor implementations observe or wrap bean instances around initialization.
- 06The ApplicationContext exposes the final managed object, which may be a proxy.
Active Recall Checkpoint
When NoSuchBeanDefinitionException occurs, what should you investigate first?
Show answer & explanation
Verify that a matching definition was registered: check XML resources, configuration imports, scan boundaries, bean names and types, profiles, and conditional configuration. Dependency resolution cannot select a bean that was never registered.
A strong interview summary
Working Implementation
Code Walkthrough
Load the same PaymentService graph with ClassPathXmlApplicationContext and AnnotationConfigApplicationContext, then compare the registered bean names and types.
package com.example.core;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class XmlVsJavaConfigLab {
public record InventoryClient(String warehouseUrl) {}
public record OrderProcessor(InventoryClient inventory) {}
@Configuration
// Hybrid migration support: @ImportResource("classpath:legacy-beans.xml")
public static class ModernConfig {
@Bean
InventoryClient inventoryClient() {
return new InventoryClient("https://warehouse-eu.internal/api/v2");
}
@Bean
OrderProcessor orderProcessor(InventoryClient inventory) {
return new OrderProcessor(inventory);
}
}
public static void main(String[] args) {
// Both XML <bean> tags and Java @Bean methods populate the exact same BeanDefinitionRegistry
try (var context = new AnnotationConfigApplicationContext(ModernConfig.class)) {
OrderProcessor processor = context.getBean(OrderProcessor.class);
System.out.println("Warehouse configured: " + processor.inventory().warehouseUrl());
System.out.println("Registered bean definition count: " + context.getBeanDefinitionNames().length);
}
}
}Synthesis & Production Verification
Deliberate Failure Condition
- Break: Mix XML, component scanning, and Java configuration without knowing which source owns a bean
- Observe: Duplicate names, surprising overrides, or NoSuchBeanDefinitionException at startup
- Repair: Trace configuration metadata to the BeanDefinition registry before debugging object creation.
Production Acceptance Criteria
- Map an XML bean element to an equivalent @Bean method
- Explain what component scanning registers
- Choose explicit Java configuration for third-party objects and scanning for application components
Key Takeaway
XML, @Bean methods, component scanning, and Boot auto-configuration are different sources of BeanDefinition metadata consumed by the same Spring container.
Architectural & Technical Review
Core Interview Questions
Q01How is an XML bean element related to an @Bean method?Show answer
Both register bean-definition metadata. The XML id corresponds to the bean name, the class or factory method determines construction, and constructor references or method parameters describe dependencies. The authoring format differs; the container model does not.
Q02What does component scanning actually do?Show answer
It searches configured packages with type filters, finds candidate component classes, derives bean names and metadata, and registers BeanDefinition objects. Bean instances are created later by the container lifecycle.
Q03How would you diagnose NoSuchBeanDefinitionException?Show answer
First verify registration: inspect scan boundaries, configuration imports, XML resources, profiles, conditions, names, and exposed types. Only after confirming a definition exists should you investigate autowire candidate selection.
Production Pitfalls
Critical Anti-Patterns
- Pitfall: Treating XML and annotations as different dependency-injection engines — They are metadata sources for the same BeanFactory and lifecycle pipeline.
- Pitfall: Using scanning for third-party classes — Use an explicit @Bean factory method when you do not own or cannot annotate the class.
Primary Documentation & Specifications
Lesson Primary References
Supplementary Module Resources