skip to content

Component Scanning & Filters

@ComponentScan and its include/exclude filters decide which packages Spring searches and which candidates become beans. Interviewers ask about base packages and filter types when they want to know how you would keep scanning fast and deliberately scoped.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What does @ComponentScan do, and how do you tell it which packages to scan?

level: juniorimportance: must knowfreq 80%

answer

  1. scan packages → find @Component → register bean
  2. basePackages (String) vs basePackageClasses (type-safe)
  3. default = declaring class's package (Boot root package)
  4. recursive into subpackages
  5. @Service/@Repository meta-annotated with @Component

basics

~10 s

@ComponentScan tells Spring to search packages for classes annotated with @Component (and @Service, @Repository, @Controller) and register them as beans. You point it at packages with basePackages, e.g. @ComponentScan(basePackages = "com.app").

solid answer

~40 s

@ComponentScan is a configuration annotation that triggers classpath scanning: Spring walks the given packages, finds classes marked with stereotype annotations (@Component and its specializations @Service, @Repository, @Controller, plus anything meta-annotated with @Component), and registers each as a bean definition. You choose packages via basePackages (String names) or the type-safe basePackageClasses (marker classes; Spring scans their package). If you specify neither, it defaults to the package of the class that declares @ComponentScan — which is exactly why @SpringBootApplication (which includes @ComponentScan) is placed in a root package. Scanning is recursive into subpackages. @Configuration classes are themselves @Component-annotated, so they're picked up too. This is the mechanism behind classpath/annotation-based configuration versus explicit @Bean methods.

code

java · 8 lines
java
@Configuration
@ComponentScan(basePackages = {"com.app.web", "com.app.core"})
// type-safe alternative:
// @ComponentScan(basePackageClasses = {WebMarker.class, CoreMarker.class})
public class AppConfig { }

@Service // meta-annotated with @Component -> detected, bean name "orderService"
public class OrderService { }

go deeper

for a junior

Should know @ComponentScan finds @Component/@Service/etc. and registers them, and that basePackages selects packages.

for a middle

Should mention basePackageClasses type-safety, the default-package rule tied to @SpringBootApplication, recursion, and default bean naming.

for a senior

Should contrast scanning vs explicit @Bean, discuss meta-annotation detection, and when broad scanning is a smell.

for a principal

Should frame scanning as one strategy in the bean-definition-registration pipeline and reason about package/module boundaries and startup cost.

## What @ComponentScan is `@ComponentScan` is a Spring annotation, normally placed on a `@Configuration` class, that turns on **classpath scanning**. Instead of you declaring every bean by hand with a `@Bean` method, Spring searches ("scans") a set of packages, finds classes that carry a **stereotype annotation**, and automatically registers each one as a **bean definition** in the `ApplicationContext`. ### Stereotype annotations it detects - `@Component` — generic component. - `@Service`, `@Repository`, `@Controller`, `@RestController`, `@Configuration` — these are all **meta-annotated** with `@Component`, so scanning finds them too. Spring detects any class whose annotations transitively include `@Component`. ### Choosing packages - `basePackages` — one or more package names as Strings: `@ComponentScan(basePackages = {"com.app.web", "com.app.core"})`. `value` is an alias, so `@ComponentScan("com.app")` works. - `basePackageClasses` — type-safe alternative: you pass classes (often empty marker interfaces) and Spring scans the package **each class lives in**. Refactoring/renaming a package won't silently break this, unlike a hardcoded String. - **Default when nothing is given:** the package of the class that declares the annotation. That's the crucial default behind Spring Boot — `@SpringBootApplication` is a composed annotation that includes `@ComponentScan`, so putting your main class in a top-level package (e.g. `com.app`) makes Spring scan `com.app` and everything beneath it. ### Recursion Scanning is **recursive**: naming `com.app` also scans `com.app.web`, `com.app.core.impl`, etc. A common bug is placing a bean **outside** the scanned root (e.g. `com.other`) — it silently won't be registered. ### How it relates to bean definitions Each detected class becomes a `BeanDefinition`. By default the **bean name** is the simple class name with the first letter lowercased (`OrderService` → `orderService`), produced by `AnnotationBeanNameGenerator`. You can override the name via the stereotype's `value`, e.g. `@Service("orders")`. ### XML equivalent In XML config the same thing is `<context:component-scan base-package="com.app"/>`. ### When to use - Use component scanning for **your own application classes** you control and annotate. - Use explicit `@Bean` methods for **third-party classes** you can't annotate, or when you need constructor arguments/conditional wiring. ### Gotchas - Scanning too broad a package (e.g. an empty String or a very high package) is slow and may pick up unintended beans; scan only what you own. - A class must be **concrete and instantiable** and have a usable constructor to become a bean; abstract classes/interfaces are skipped (unless matched by custom filters as candidates). - Only annotated classes are found by default — a plain POJO with no stereotype is invisible to scanning.

  • Why does the location of the @SpringBootApplication class matter?
    @SpringBootApplication bundles @ComponentScan with no basePackages, so it defaults to the main class's own package and scans it recursively. Put the class in a root package or beans in sibling packages won't be found.
  • What's the default bean name for a scanned class?
    The uncapitalized simple class name (OrderService -> orderService), generated by AnnotationBeanNameGenerator. Override it via the stereotype value, e.g. @Service("orders").

saying these in an interview costs you the question

  • Thinking @ComponentScan registers every class on the classpath rather than only annotated stereotypes
  • Believing scanning is not recursive into subpackages
  • Claiming a plain POJO without any annotation gets picked up by default scanning
  • Not knowing the default is the declaring class's package

context

open as a page

How do includeFilters and excludeFilters work, and what are the FilterType options?

level: middleimportance: must knowfreq 60%

basics

~10 s

@ComponentScan can narrow what it registers using includeFilters (register extra matching classes) and excludeFilters (skip matching classes). Each filter has a FilterType: ANNOTATION, ASSIGNABLE_TYPE, ASPECTJ, REGEX, or CUSTOM.

open as a page

When should you prefer component scanning over explicit @Bean methods, and what are the tradeoffs?

level: middleimportance: should knowfreq 35%

basics

~10 s

Use 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.

open as a page

How are bean names assigned during component scanning, and how do you customize them with BeanNameGenerator?

level: seniorimportance: should knowfreq 30%

basics

~20 s

By default a scanned bean's name is the class's simple name with a lowercased first letter (OrderService → orderService), or the value you pass to the stereotype (@Service("x")). You override the strategy with a BeanNameGenerator via @ComponentScan(nameGenerator = ...).

open as a page

What is ClassPathScanningCandidateComponentProvider and when would you use it directly?

level: seniorimportance: should knowfreq 30%

basics

~20 s

It's the low-level engine behind @ComponentScan: given base packages and filters, it scans the classpath and returns candidate BeanDefinitions. You use it directly to find annotated/typed classes yourself — outside the normal bean registration flow.

open as a page