Skip to main content

Week 1 Day 5 — Component Scanning and Package Structure

Goal

Today I want to understand how Spring finds my classes and registers them as beans.

Main questions:

  1. What is component scanning?
  2. What does @ComponentScan do?
  3. What does @SpringBootApplication scan by default?
  4. Why does package structure matter?
  5. Why can a class with @Service still not become a bean?
  6. How can I customize component scanning?
  7. What are stereotype annotations?
  8. What are common real-world bugs with component scanning?
  9. What are common exam traps?

1. Quick Review

From previous days:

  • A Spring bean is an object managed by Spring.
  • Spring needs to know which classes should become beans.
  • Beans can be registered with @Component, @Service, @Repository, @Controller, @RestController, or @Bean.
  • ApplicationContext stores and manages beans.
  • BeanDefinition is metadata for creating a bean.

Today I focus on this question:

How does Spring find my annotated classes?

The answer is:

Component scanning.


2. What Is Component Scanning?

Component scanning means:

Spring scans packages to find classes annotated with Spring stereotype annotations and registers them as beans.

Example:

@Service
public class OrderService {
}

This class can become a bean only if Spring scans the package where this class is located.

Important sentence:

Annotation alone is not enough. The class must also be inside the component scan path.


3. What Does Spring Look For?

During component scanning, Spring looks for annotations such as:

@Component
@Service
@Repository
@Controller
@RestController
@Configuration

These are called stereotype annotations.

If Spring finds one of these annotations, it can register a BeanDefinition.

Later, it creates the actual bean.


4. Component Scanning Flow

Simplified flow:

1. Spring application starts.
2. ApplicationContext is created.
3. Spring checks the component scan base package.
4. Spring scans classes inside that package and subpackages.
5. Spring finds annotations like @Service and @Repository.
6. Spring registers BeanDefinitions.
7. Spring creates beans.
8. Spring injects dependencies.

Memory sentence:

Component scanning finds classes. Bean creation creates objects.


5. @ComponentScan

The annotation responsible for scanning is:

@ComponentScan

Example:

@Configuration
@ComponentScan("com.example.app")
public class AppConfig {
}

This tells Spring:

Scan com.example.app and its subpackages.

So Spring scans:

com.example.app
com.example.app.service
com.example.app.repository
com.example.app.controller

6. Spring Boot and @SpringBootApplication

In Spring Boot, we usually do not write @ComponentScan directly.

We write:

@SpringBootApplication
public class MyApplication {
}

But @SpringBootApplication already includes:

@Configuration
@EnableAutoConfiguration
@ComponentScan

Very important exam sentence:

@SpringBootApplication includes @ComponentScan.


7. Default Scan Package in Spring Boot

Spring Boot starts scanning from the package where the main application class is located.

Example:

package com.example.kanzlei;

@SpringBootApplication
public class KanzleiApplication {
}

Spring scans:

com.example.kanzlei
com.example.kanzlei.controller
com.example.kanzlei.service
com.example.kanzlei.repository
com.example.kanzlei.config

It scans the main package and all subpackages.


8. Good Package Structure

Good structure:

com.example.kanzlei
├── KanzleiApplication.java
├── controller
│ └── TaskController.java
├── service
│ └── TaskService.java
├── repository
│ └── TaskRepository.java
├── entity
│ └── Task.java
├── dto
│ └── TaskResponse.java
└── config
└── SecurityConfig.java

This is good because the main class is in the root package:

com.example.kanzlei

All other classes are under it.

Spring can scan everything.


9. Bad Package Structure

Bad structure:

com.example.app
└── KanzleiApplication.java

com.example.service
└── TaskService.java

com.example.repository
└── TaskRepository.java

If the main class is in:

com.example.app

Spring scans:

com.example.app

But it does not automatically scan:

com.example.service
com.example.repository

So TaskService and TaskRepository may not become beans.


10. Real Bug Example

Imagine this class exists:

package com.example.service;

@Service
public class TaskService {
}

And the main class is:

package com.example.app;

@SpringBootApplication
public class MyApplication {
}

Spring scans:

com.example.app

But TaskService is in:

com.example.service

Result:

TaskService is not found.
TaskService is not registered as a bean.
Application may fail with "No qualifying bean of type TaskService".

11. Best Practice

Put your main application class in the root package.

Good:

com.steve.klarsync
├── KlarsyncApplication.java
├── task
├── user
├── client
├── document
└── config

Bad:

com.steve.klarsync.app
└── KlarsyncApplication.java

com.steve.klarsync.task
com.steve.klarsync.user
com.steve.klarsync.client

Why bad?

Because com.steve.klarsync.task is not under com.steve.klarsync.app.


12. Simple Rule

Use this rule:

The main Spring Boot application class should be placed in the highest/root package of the application.

Example:

package de.klarsync;

@SpringBootApplication
public class KlarsyncApplication {
}

Then put other packages under:

de.klarsync.task
de.klarsync.user
de.klarsync.client
de.klarsync.security
de.klarsync.config

13. Stereotype Annotations

These annotations help Spring understand the role of a class.

@Component

Generic Spring-managed component.

@Component
public class SlugGenerator {
}

Use when the class does not clearly belong to service, repository, or controller layer.


@Service

Business logic layer.

@Service
public class TaskService {
}

Use for application services and domain use cases.


@Repository

Persistence layer.

@Repository
public class JdbcTaskRepository {
}

Use for classes that talk to the database.

Special point:

@Repository can enable persistence exception translation.


@Controller

Spring MVC controller for returning views.

@Controller
public class HomeController {
}

Usually used for server-rendered HTML pages.


@RestController

REST API controller.

@RestController
@RequestMapping("/api/tasks")
public class TaskController {
}

@RestController includes:

@Controller
@ResponseBody

@Configuration

Configuration class.

@Configuration
public class AppConfig {
}

Often contains @Bean methods.


14. Important: @Configuration Is Also a Component

@Configuration is also discovered by component scanning.

Example:

@Configuration
public class TimeConfig {

@Bean
public Clock clock() {
return Clock.systemUTC();
}
}

If TimeConfig is inside the scan path, Spring finds it.

Then Spring processes the @Bean method and registers Clock as a bean.


15. @Bean Still Needs Configuration Class Registration

Example:

@Configuration
public class TimeConfig {

@Bean
public Clock clock() {
return Clock.systemUTC();
}
}

This works if TimeConfig is found by component scanning.

But if TimeConfig is outside the scan path, Spring does not find it.

Then the clock bean is not registered.

Exam trap:

@Bean methods are only processed if the configuration class itself is registered.


16. How to Customize Component Scanning

You can explicitly define scan packages.

Example:

@SpringBootApplication(scanBasePackages = "com.example")
public class MyApplication {
}

This tells Spring to scan:

com.example

Another way:

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

17. Multiple Base Packages

You can scan multiple packages:

@SpringBootApplication(scanBasePackages = {
"com.example.app",
"com.example.shared"
})
public class MyApplication {
}

Or:

@ComponentScan(basePackages = {
"com.example.app",
"com.example.shared"
})

But best practice is still:

Put your application class in the root package and avoid custom scan configuration unless necessary.


18. Type-Safe Alternative: basePackageClasses

Instead of writing package names as strings, you can use classes.

Example:

@ComponentScan(basePackageClasses = {
TaskService.class,
SharedConfig.class
})
public class AppConfig {
}

This is safer because refactoring class packages is easier than updating string package names manually.


19. Include and Exclude Filters

@ComponentScan can include or exclude classes.

Example:

@ComponentScan(
basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Deprecated.class
)
)

This is more advanced.

For the certification, know that component scanning can be customized, but most questions focus on default scanning.


20. Real Question: Why Is My Service Not Injected?

Example error:

Parameter 0 of constructor in TaskController required a bean of type 'TaskService' that could not be found.

Possible reasons:

  1. TaskService has no @Service, @Component, or @Bean.
  2. TaskService is outside the scanned package.
  3. TaskService has a profile that is not active.
  4. TaskService is conditional and the condition is false.
  5. TaskService cannot be created because one of its dependencies is missing.
  6. The wrong class or package is imported.
  7. The test slice does not load this bean.

Most common reasons:

Missing annotation
Outside component scan
Missing dependency

21. Real Question: Does @Service Always Create a Bean?

No.

This class:

@Service
public class TaskService {
}

becomes a bean only if Spring scans the package containing it.

So the correct answer is:

@Service marks the class as a candidate for component scanning. It becomes a bean only if it is discovered by the scan.


22. Real Question: Does @ComponentScan Scan the Whole Project?

No.

By default, it scans from a base package.

In Spring Boot, the base package is usually the package of the class annotated with @SpringBootApplication.

It does not automatically scan the whole source code.


23. Real Question: Does Spring Scan External Libraries?

Not automatically in the same way.

Spring scans configured base packages.

But Spring Boot auto-configuration can register beans from libraries through a different mechanism.

Important distinction:

Component scanning finds my annotated classes.
Auto-configuration registers framework/library beans based on conditions.

Example:

  • My TaskService is found by component scanning.
  • Spring Boot creates DispatcherServlet through auto-configuration.

24. Component Scanning vs Auto-Configuration

TopicComponent ScanningAuto-Configuration
PurposeFind my classesConfigure Spring Boot infrastructure
Based onpackages and annotationsclasspath, properties, conditions
Example@Service TaskServiceembedded Tomcat, DispatcherServlet
Annotation@ComponentScan@EnableAutoConfiguration
Included in@SpringBootApplication@SpringBootApplication

Memory sentence:

Component scanning finds my beans. Auto-configuration creates Spring Boot infrastructure beans.


25. Component Scanning vs @Bean

TopicComponent Scanning@Bean
How bean is registeredSpring finds annotated classMethod return value becomes bean
Best forMy own classesThird-party/custom objects
Example@Service TaskService@Bean Clock
Requires scan?class must be scannedconfig class must be registered

26. Component Scanning and Tests

Sometimes a bean works in the real app but not in a test.

Example:

@WebMvcTest(TaskController.class)
class TaskControllerTest {
}

This test only loads the web layer.

It does not load all services.

So this may fail:

No qualifying bean of type TaskService

Fix:

@MockBean
private TaskService taskService;

Important:

Test slice annotations load only part of the application context.

This is not exactly a component scanning problem, but it looks similar.


27. Component Scanning and Profiles

A class may be scanned but not active because of a profile.

Example:

@Service
@Profile("prod")
public class RealEmailService {
}

This bean is created only when the prod profile is active.

If the active profile is dev, Spring does not create it.


28. Component Scanning and Conditional Beans

A class may be conditional.

Example:

@Component
@ConditionalOnProperty(name = "feature.audit.enabled", havingValue = "true")
public class AuditService {
}

This bean is created only if the property matches.

If not, Spring skips it.

This is common in Spring Boot.


29. Component Scanning and Bean Names

Default bean name uses the class name with lowercase first letter.

Example:

@Service
public class TaskService {
}

Bean name:

taskService

Example:

@Component
public class EmailNotificationSender {
}

Bean name:

emailNotificationSender

Custom name:

@Service("mainTaskService")
public class TaskService {
}

Bean name:

mainTaskService

30. Component Scanning and Interfaces

Spring cannot instantiate an interface directly.

Example:

public interface PaymentProvider {
}

This alone is not a bean.

Spring needs an implementation:

@Component
public class StripePaymentProvider implements PaymentProvider {
}

Then Spring can inject by interface type:

@Service
public class CheckoutService {

public CheckoutService(PaymentProvider paymentProvider) {
}
}

This works if there is exactly one implementation bean.


31. Component Scanning and Abstract Classes

Spring cannot normally instantiate abstract classes.

Example:

@Component
public abstract class BaseService {
}

This is not useful as a normal bean because Spring cannot create an abstract class instance.

But subclasses can be beans:

@Service
public class TaskService extends BaseService {
}

32. Component Scanning and Inner Classes

Spring usually scans top-level classes.

Static nested classes can sometimes be registered, especially in configuration or tests, but normal application components should be top-level classes.

Best practice:

Keep Spring components as clear top-level classes.


33. Component Scanning and Final Classes

A final class can be registered as a bean.

But final classes can be problematic when Spring needs to create a class-based proxy, for example for AOP or transactions.

Example:

@Service
public final class PaymentService {
}

The bean may be created.

But proxying can become a problem later.

We will study proxies in AOP week.


34. Component Scanning and Kotlin

In Kotlin, classes are final by default.

Spring often needs classes to be open for proxying.

That is why Kotlin Spring projects often use:

kotlin("plugin.spring")

This opens Spring-annotated classes automatically.

This is useful for your Kotlin/Spring background.

Exam focus is usually Java, but the proxy idea is important.


35. Real Debug Checklist

When a bean is not found, check this:

## Bean Not Found Debug Checklist

[ ] Does the class have `@Component`, `@Service`, `@Repository`, `@Controller`, `@RestController`, or is it created by `@Bean`?
[ ] Is the class inside the package scanned by Spring?
[ ] Is the main application class in the root package?
[ ] Is the active profile correct?
[ ] Does the bean have a condition that is false?
[ ] Are all constructor dependencies available?
[ ] Am I using a test slice like `@WebMvcTest` or `@DataJpaTest`?
[ ] Did I import the correct annotation package?
[ ] Is the class concrete, not abstract?
[ ] Is there a circular dependency?

36. Real Exam Question: Package Structure

Question:

package com.example.app;

@SpringBootApplication
public class MyApplication {
}
package com.example.service;

@Service
public class UserService {
}

Will UserService be discovered automatically?

Answer:

No. By default, Spring Boot scans from the package of the main application class, which is com.example.app. UserService is in com.example.service, which is not a subpackage of com.example.app. Therefore it will not be discovered unless scanning is customized.


37. Real Exam Question: Good Package Structure

Question:

package com.example;

@SpringBootApplication
public class MyApplication {
}
package com.example.service;

@Service
public class UserService {
}

Will UserService be discovered?

Answer:

Yes. The main application class is in com.example, so Spring scans com.example and its subpackages. com.example.service is a subpackage, so UserService can be discovered.


38. Real Exam Question: @SpringBootApplication

Question:

What three annotations are included in @SpringBootApplication?

Answer:

@SpringBootApplication includes:

@Configuration
@EnableAutoConfiguration
@ComponentScan

39. Real Exam Question: @Service

Question:

Does @Service itself guarantee that a class becomes a Spring bean?

Answer:

No. @Service marks the class as a candidate for component scanning. The class becomes a bean only if it is found by component scanning or otherwise registered.


40. Real Exam Question: @Bean

Question:

@Configuration
public class AppConfig {

@Bean
public Clock clock() {
return Clock.systemUTC();
}
}

What becomes the bean?

Answer:

The return value of the clock() method becomes a Spring bean. By default, the bean name is clock, and the bean type is Clock.


41. Real Exam Question: Config Outside Scan

Question:

If AppConfig contains a @Bean method but AppConfig itself is outside component scanning, will the bean be created?

Answer:

No, not automatically. The configuration class must be registered with Spring. If it is outside component scanning and not imported or otherwise registered, Spring will not process its @Bean methods.


42. Real Exam Question: Component Scan Base Package

Question:

Where does Spring Boot start component scanning by default?

Answer:

Spring Boot starts component scanning from the package of the class annotated with @SpringBootApplication and scans its subpackages.


43. Real Exam Question: Custom Scan

Question:

How can I tell Spring Boot to scan another package?

Answer:

I can use:

@SpringBootApplication(scanBasePackages = "com.example")
public class MyApplication {
}

or use:

@ComponentScan(basePackages = "com.example")

44. Real Exam Question: Component Scan vs Auto-Configuration

Question:

What is the difference between component scanning and auto-configuration?

Answer:

Component scanning finds application classes annotated with stereotypes such as @Component, @Service, and @Repository. Auto-configuration creates Spring Boot infrastructure beans based on classpath, properties, existing beans, and conditions. Component scanning is for my application beans; auto-configuration is for Boot-provided setup.


45. Real Exam Question: Bean Not Found

Question:

What are common reasons for this error?

No qualifying bean of type 'EmailService' available

Answer:

Common reasons are: EmailService is not annotated or registered with @Bean, it is outside the component scan path, its active profile does not match, a condition prevents it from being created, one of its dependencies is missing, or the current test slice does not load it.


46. Interview Answer

Question:

What is component scanning in Spring?

Good answer:

Component scanning is the process where Spring scans configured packages to find classes annotated with stereotype annotations such as @Component, @Service, @Repository, and @Controller. When Spring finds these classes, it registers bean definitions for them and later creates the actual beans. In Spring Boot, component scanning is enabled by @SpringBootApplication, which includes @ComponentScan. By default, Spring Boot scans from the package of the main application class and its subpackages.


47. Interview Answer

Question:

Why should the main Spring Boot class be placed in the root package?

Good answer:

The main Spring Boot class should be placed in the root package because Spring Boot starts component scanning from the package of the class annotated with @SpringBootApplication. If the main class is too deep in the package structure, Spring may not scan services, repositories, controllers, or configuration classes in sibling packages. Placing the main class in the root package ensures that all subpackages are scanned automatically.


48. Interview Answer

Question:

Why can a class annotated with @Service still not be found?

Good answer:

A class annotated with @Service may not be found if it is outside the component scan path. The annotation marks it as a candidate for component scanning, but Spring still has to scan its package. Other reasons include missing active profiles, conditional annotations, missing constructor dependencies, or test slices that do not load the full application context.


49. Interview Answer

Question:

What is the difference between component scanning and @Bean registration?

Good answer:

Component scanning registers beans by finding classes annotated with stereotypes such as @Component, @Service, or @Repository. This is usually used for application classes that I own. @Bean registration happens when Spring calls a method inside a configuration class and registers the return value as a bean. This is useful for third-party objects or objects that need custom creation logic.


50. Tiny Code Practice

Create this structure:

de.klarsync
├── KlarsyncApplication.java
├── task
│ ├── TaskController.java
│ └── TaskService.java
└── config
└── TimeConfig.java

Main class:

package de.klarsync;

@SpringBootApplication
public class KlarsyncApplication {

public static void main(String[] args) {
SpringApplication.run(KlarsyncApplication.class, args);
}
}

Service:

package de.klarsync.task;

@Service
public class TaskService {
}

Config:

package de.klarsync.config;

@Configuration
public class TimeConfig {

@Bean
public Clock clock() {
return Clock.systemUTC();
}
}

Question:

Will TaskService and Clock be registered as beans?

Answer:

Yes. KlarsyncApplication is in de.klarsync, so Spring scans de.klarsync and all subpackages. It finds TaskService in de.klarsync.task and TimeConfig in de.klarsync.config. Then it processes the @Bean method and creates the Clock bean.


51. Tiny Bug Practice

Bad structure:

de.klarsync.app
└── KlarsyncApplication.java

de.klarsync.task
└── TaskService.java

Main class:

package de.klarsync.app;

@SpringBootApplication
public class KlarsyncApplication {
}

Service:

package de.klarsync.task;

@Service
public class TaskService {
}

Question:

Will TaskService be discovered?

Answer:

No. Spring scans from de.klarsync.app. The package de.klarsync.task is not a subpackage of de.klarsync.app. So TaskService is outside the default scan path.

Possible fixes:

  1. Move the main class to de.klarsync.
  2. Use scanBasePackages = "de.klarsync".
  3. Use explicit @ComponentScan.

Best fix:

Move the main class to the root package.

Practice Questions and Answers

Question 1

What is component scanning?

Answer:

Component scanning is the process where Spring scans configured packages to find classes annotated with stereotype annotations such as @Component, @Service, @Repository, and @Controller. Spring registers these classes as bean definitions and later creates beans from them.


Question 2

What annotation enables component scanning?

Answer:

Component scanning is enabled by @ComponentScan.


Question 3

Does @SpringBootApplication include @ComponentScan?

Answer:

Yes. @SpringBootApplication includes @ComponentScan, together with @Configuration and @EnableAutoConfiguration.


Question 4

Where does Spring Boot start scanning by default?

Answer:

Spring Boot starts scanning from the package of the class annotated with @SpringBootApplication and scans its subpackages.


Question 5

Why should the main Spring Boot class be in the root package?

Answer:

The main class should be in the root package so that Spring scans all application subpackages automatically. If the main class is too deep, sibling packages may not be scanned.


Question 6

Does @Service always guarantee that a class becomes a bean?

Answer:

No. @Service marks a class as a candidate for component scanning. It becomes a bean only if Spring scans its package or it is otherwise registered.


Question 7

What are stereotype annotations?

Answer:

Stereotype annotations are annotations that mark a class as a Spring-managed component and also express its role in the application, such as service, repository, or controller.


Question 8

Name five stereotype annotations.

Answer:

Five stereotype annotations are:

@Component
@Service
@Repository
@Controller
@RestController

Also important:

@Configuration

Question 9

What is the difference between @Component and @Service?

Answer:

@Component is a generic Spring-managed component. @Service is a specialization of @Component used for service-layer classes that contain business logic.


Question 10

What is special about @Repository?

Answer:

@Repository marks a persistence-layer class and can enable persistence exception translation into Spring’s DataAccessException hierarchy.


Question 11

What does @RestController include?

Answer:

@RestController includes @Controller and @ResponseBody.


Question 12

What is the difference between component scanning and @Bean?

Answer:

Component scanning registers beans by finding annotated classes. @Bean registers the return value of a method inside a configuration class. Component scanning is usually used for my own classes, while @Bean is useful for third-party or custom-created objects.


Question 13

What must happen for a @Bean method to be processed?

Answer:

The configuration class containing the @Bean method must itself be registered with Spring, usually by component scanning, @Import, or direct configuration registration.


Question 14

What is the default bean name for this class?

@Service
public class EmailService {
}

Answer:

The default bean name is:

emailService

Question 15

Will this service be scanned?

package com.example.app;

@SpringBootApplication
public class MyApplication {
}
package com.example.app.service;

@Service
public class UserService {
}

Answer:

Yes. UserService is in com.example.app.service, which is a subpackage of com.example.app.


Question 16

Will this service be scanned?

package com.example.app;

@SpringBootApplication
public class MyApplication {
}
package com.example.service;

@Service
public class UserService {
}

Answer:

No. com.example.service is not a subpackage of com.example.app, so it is outside the default scan path.


Question 17

How can I customize the scan base package?

Answer:

I can customize the scan base package with:

@SpringBootApplication(scanBasePackages = "com.example")

or:

@ComponentScan(basePackages = "com.example")

Question 18

What is the difference between component scanning and auto-configuration?

Answer:

Component scanning finds my application classes annotated with stereotypes like @Service or @Repository. Auto-configuration creates Spring Boot infrastructure beans based on classpath, properties, existing beans, and conditions.


Question 19

Why might a bean not be found even though the class has @Service?

Answer:

Possible reasons include: the class is outside component scanning, missing active profile, false condition, missing constructor dependency, test slice does not load the bean, wrong annotation import, or the class cannot be instantiated.


Question 20

What should I check when I see No qualifying bean of type ... available?

Answer:

I should check: annotation, package scan path, main application class location, active profile, conditions, constructor dependencies, test slice configuration, correct imports, and whether the class is concrete.

Final Memory Sentences

  • Component scanning finds annotated classes and registers them as beans.
  • @ComponentScan enables component scanning.
  • @SpringBootApplication includes @ComponentScan.
  • Spring Boot scans from the package of the main application class by default.
  • The main application class should be in the root package.
  • @Service is only a candidate unless Spring scans it.
  • @Configuration classes must be registered for their @Bean methods to run.
  • Component scanning finds my application beans.
  • Auto-configuration creates Spring Boot infrastructure beans.
  • @Component is generic.
  • @Service is for business logic.
  • @Repository is for persistence and exception translation.
  • @RestController equals @Controller plus @ResponseBody.
  • A bean not found error often means missing annotation, wrong package, inactive profile, false condition, or missing dependency.