When should you prefer component scanning over explicit @Bean methods, and what are the tradeoffs?
answer
- scan = your annotated classes; @Bean = third-party/legacy
- @Bean for conditional / multiple instances / custom construction
- scanning = concise but 'magic'; @Bean = explicit but verbose
- hybrid is idiomatic (scan app, declare infra)
- exclude filter can't remove a @Bean-defined bean
basics
~10 sUse component scanning (@Component/@ComponentScan) for your own annotated classes — it's concise and auto-wires by constructor. Use explicit @Bean methods for third-party classes you can't annotate or when you need custom construction/conditional logic.
solid answer
~40 sComponent scanning is convention-driven: annotate your own classes with stereotypes and Spring auto-detects and wires them. It's terse and keeps wiring next to the class, ideal for the bulk of application code you control. Explicit @Bean methods in @Configuration classes are declaration-driven: you control instantiation fully. Prefer @Bean when the class is third-party/legacy (you can't add @Component), when construction needs logic, multiple beans of one type with different config, or conditional creation (@Conditional, profiles). Tradeoffs: scanning can be 'magic' — harder to see the full bean set, risks picking up unintended classes, and needs correct package placement; @Bean is explicit and greppable but verbose and centralizes wiring. Many codebases combine both: scan application components, declare infrastructure/third-party beans explicitly. Note both produce BeanDefinitions ultimately handled by the same container.
go deeper
Should know @Component-scanning for own classes and @Bean for others, at a basic level.
Should articulate the tradeoffs and the third-party/conditional/multiple-instance cases for @Bean.
Should note the hybrid pattern, override conflicts, and @Configuration proxyBeanMethods interception difference.
Should reason about maintainability/discoverability, startup cost, and module boundaries when choosing a wiring strategy across a large codebase.
## Two ways to define beans Spring registers beans as `BeanDefinition`s regardless of source. The two idiomatic sources: ### 1. Component scanning (annotation/convention based) You put `@Component`/`@Service`/`@Repository`/`@Controller` on **your own** classes and enable `@ComponentScan` (implicit in `@SpringBootApplication`). Spring finds them and instantiates via their (usually single) constructor, injecting dependencies by type. - **Pros:** minimal boilerplate; wiring intent lives on the class; scales to many classes without editing a central file; constructor injection is automatic. - **Cons:** implicit/"magical" — no single place lists all beans; wrong package placement silently drops beans; broad scanning can register unintended classes; you can't annotate code you don't own. ### 2. Explicit @Bean methods (Java config) Inside a `@Configuration` class you write factory methods: ```java @Bean DataSource dataSource(DataSourceProperties props) { return build(props); } ``` - **Pros:** full control of construction; works for **third-party/legacy** classes you can't annotate; easy to create **multiple beans of the same type** with different settings; natural home for `@Conditional`, `@Profile`, `@Primary`, `@Scope` decisions; explicit and greppable. - **Cons:** verbose; centralizes wiring away from the class; more code to maintain. ### When to choose which - **Your application services/controllers/repositories** → component scanning. - **Infrastructure and third-party objects** (DataSource, RestClient, ObjectMapper, a library's client) → `@Bean`. - **Conditional / environment-specific / multiple-instance** wiring → `@Bean` (clearer than annotation gymnastics). - **Framework-provided auto-config** already uses `@Bean` heavily under the hood. ### Common hybrid Most real apps do both: `@SpringBootApplication` scans your packages, while `@Configuration` classes declare the handful of infrastructure beans. This is idiomatic, not a smell. ### Relation to filters/scanning topic Exclude filters can keep scanning from grabbing a class, but they **cannot** remove a bean you created with `@Bean` — the two mechanisms are independent. If you both scan a `@Component` and declare a `@Bean` of the same name, you get an **override conflict** (error by default in Boot). ### Gotchas - Don't annotate a class **and** also declare it as a `@Bean` — duplicate/override. - Over-broad `@ComponentScan` slows startup and may register test doubles or unintended classes. - `@Bean` methods on a `@Configuration` (proxyBeanMethods=true) class are intercepted so inter-bean method calls return the singleton; on a plain `@Component` they are not — a subtle wiring difference.
- You need two DataSource beans with different URLs. Scanning or @Bean?@Bean methods — you can't produce two differently-configured instances of the same third-party type via a single scanned class; declare each explicitly and mark one @Primary or qualify them.
saying these in an interview costs you the question
- Claiming @Bean and @Component are interchangeable in all cases
- Saying you can annotate third-party jar classes with @Component to scan them
- Thinking an excludeFilter removes a @Bean-declared bean
- Believing scanning is always preferable / never has downsides