How do I inject dependencies using constructor injection?

Use constructor injection by declaring your dependency as a private final field and accepting it as a constructor parameter. Spring will create the dependency bean and pass it into the constructor automatically.

Example:

import org.springframework.stereotype.Component;

@Component
public class MyDependency {

    public void doSomething() {
        System.out.println("Dependency logic executed.");
    }
}
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private final MyDependency myDependency;

    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void doWork() {
        myDependency.doSomething();
    }
}

Spring can inject MyDependency because:

  1. MyDependency is a Spring bean, for example annotated with @Component.
  2. MyService is also a Spring bean, for example annotated with @Service.
  3. MyService has a constructor that requires MyDependency.

In modern Spring, if the class has only one constructor, you usually do not need @Autowired:

@Service
public class MyService {

    private final MyDependency myDependency;

    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
}

If you use Lombok, you can make it shorter:

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MyService {

    private final MyDependency myDependency;

    public void doWork() {
        myDependency.doSomething();
    }
}

Constructor injection is recommended because it makes dependencies explicit, allows fields to be final, improves testability, and prevents partially initialized objects.

How do I use @Component, @Service, and @Repository correctly?

Short Answer

Use these annotations according to the role of the class:

Annotation Use for Typical layer
@Component Generic Spring-managed class Utility/infrastructure/helper
@Service Business logic Service layer
@Repository Data access / persistence Repository/DAO layer

All three make the class a Spring bean, meaning Spring can create it, manage it, and inject it into other beans.


1. @Component: Generic Spring Bean

Use @Component when the class should be managed by Spring but does not clearly belong to the service, repository, or controller layer.

import org.springframework.stereotype.Component;

@Component
public class FileNameGenerator {

    public String generate(String originalName) {
        return System.currentTimeMillis() + "-" + originalName;
    }
}

Good uses for @Component:

  • formatters
  • mappers
  • validators
  • helpers
  • schedulers
  • adapters
  • general infrastructure classes

If a class contains business logic, prefer @Service instead.


2. @Service: Business Logic

Use @Service for classes that represent application/business operations.

import org.springframework.stereotype.Service;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee getEmployee(Long id) {
        return employeeRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));
    }
}

Good uses for @Service:

  • coordinating business workflows
  • applying business rules
  • calling repositories
  • calling external APIs
  • handling transactions

Example:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PayrollService {

    private final EmployeeRepository employeeRepository;

    public PayrollService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @Transactional
    public void processPayroll(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));

        // business logic here
    }
}

@Service is technically a specialized @Component, but it communicates intent:
this class contains business/service logic.


3. @Repository: Database/Data Access

Use @Repository for persistence classes: DAOs, database gateways, or repositories.

With Spring Data JPA, you usually define an interface:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

For Spring Data JPA interfaces, @Repository is often optional because Spring Data can detect repository interfaces automatically, but adding it is still common and makes the role explicit.

Use @Repository for:

  • JPA repositories
  • JDBC DAOs
  • persistence adapters
  • custom database access classes

Example custom DAO:

import jakarta.persistence.EntityManager;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeDao {

    private final EntityManager entityManager;

    public EmployeeDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public Employee findById(Long id) {
        return entityManager.find(Employee.class, id);
    }
}

@Repository also has an extra Spring meaning: it can participate in persistence exception translation, where database-specific exceptions are translated into Spring’s data access exception hierarchy.


4. Recommended Layering

A typical Spring MVC + Spring Data JPA flow looks like this:

Controller -> Service -> Repository -> Database

Example:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmployeeController {

    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees/{id}")
    public Employee getEmployee(@PathVariable Long id) {
        return employeeService.getEmployee(id);
    }
}
import org.springframework.stereotype.Service;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee getEmployee(Long id) {
        return employeeRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));
    }
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

5. Prefer Constructor Injection

For all of these beans, prefer constructor injection:

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final PaymentClient paymentClient;

    public OrderService(PaymentClient paymentClient) {
        this.paymentClient = paymentClient;
    }

    public void placeOrder() {
        paymentClient.charge();
    }
}

Avoid field injection like this:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private PaymentClient paymentClient;
}

Field injection works, but constructor injection is usually better because:

  • dependencies are explicit
  • fields can be final
  • the class is easier to test
  • the object cannot be created without required dependencies

If you use Lombok, this is common:

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class OrderService {

    private final PaymentClient paymentClient;

    public void placeOrder() {
        paymentClient.charge();
    }
}

6. Common Mistakes

Mistake 1: Using @Component for everything

This works:

@Component
public class EmployeeService {
}

But this is clearer:

@Service
public class EmployeeService {
}

Use the most specific annotation when possible.


Mistake 2: Putting business logic in repositories

Avoid this:

@Repository
public class EmployeeRepository {

    public void calculateBonusAndSaveEmployee() {
        // business rules mixed with database access
    }
}

Prefer:

Service: business rules
Repository: database access

Mistake 3: Injecting repositories directly into controllers

This is not always wrong, but for non-trivial applications it usually leads to poor layering.

Less ideal:

@RestController
public class EmployeeController {

    private final EmployeeRepository employeeRepository;

    public EmployeeController(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }
}

Better:

@RestController
public class EmployeeController {

    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }
}

The service layer gives you a place for validation, transactions, business rules, and orchestration.


7. Component Scanning Matters

Spring only finds these annotations if the classes are inside packages that Spring scans.

In Spring Boot, this usually works automatically if your main class is in the root package:

com.example.app
├── Application.java
├── controller
│   └── EmployeeController.java
├── service
│   └── EmployeeService.java
└── repository
    └── EmployeeRepository.java

If your annotated classes are outside the scanned package, Spring will not create beans for them.


Rule of Thumb

Use this:

@Component   = generic Spring-managed class
@Service     = business logic
@Repository = data access
@Controller / @RestController = web layer

For most applications:

@RestController
public class EmployeeController {
    private final EmployeeService employeeService;
}
@Service
public class EmployeeService {
    private final EmployeeRepository employeeRepository;
}
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

That is the standard and correct way to use them.

How do I understand the Spring ApplicationContext?

The Spring ApplicationContext is the central runtime container of a Spring application.

In simple terms:

ApplicationContext is the object that holds your Spring application together.

It knows:

  • which objects Spring should manage
  • how those objects are created
  • how dependencies are injected
  • which configuration values are available
  • which beans need lifecycle callbacks
  • which features like transactions, events, MVC, or JPA are enabled

1. The Short Definition

A Spring ApplicationContext is a container for Spring beans.

A bean is an object managed by Spring.

For example, if you have:

@Service
public class UserService {
}

Spring creates an instance of UserService and stores/manages it inside the ApplicationContext.

Conceptually:

ApplicationContext
 ├── userService
 ├── userRepository
 ├── orderService
 ├── dataSource
 ├── transactionManager
 └── many internal Spring infrastructure beans

2. Why Does Spring Need an ApplicationContext?

Without Spring, you create and connect objects yourself:

UserRepository repository = new UserRepository();
UserService service = new UserService(repository);

With Spring, you describe the objects and dependencies, and Spring does the wiring:

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
@Repository
public class UserRepository {
}

Spring sees both classes, creates both objects, and injects UserRepository into UserService.

The place where Spring manages all of this is the ApplicationContext.


3. What the ApplicationContext Contains

The ApplicationContext contains two broad categories of things:

Your application beans

Examples:

UserController
UserService
UserRepository
OrderService
PaymentService

These are the objects you usually write.

Spring infrastructure beans

Examples:

DataSource
EntityManagerFactory
TransactionManager
MessageSource
ConversionService
HandlerMapping
BeanPostProcessor

These are objects Spring uses internally to provide features like:

  • dependency injection
  • transactions
  • validation
  • Spring MVC routing
  • database integration
  • event publishing
  • configuration loading

So the context contains both your application and the framework infrastructure around it.


4. What Happens When the ApplicationContext Starts?

When a Spring application starts, Spring creates an ApplicationContext.

A simplified startup flow looks like this:

1. Create the ApplicationContext
2. Read configuration classes, annotations, properties, and component scans
3. Discover bean definitions
4. Decide which beans should exist
5. Create singleton beans
6. Inject dependencies
7. Run bean lifecycle callbacks
8. Apply bean post-processors
9. Create proxies if needed
10. Publish startup events
11. Application is ready

A key detail: Spring first builds bean definitions, then creates actual bean instances.


5. Bean Definition vs. Bean Instance

This distinction helps a lot.

A bean definition is Spring’s recipe for creating a bean.

It includes information like:

Bean name: userService
Bean type: UserService
Scope: singleton
Dependencies: userRepository
Initialization method: maybe present
Lazy or eager: depends on configuration

A bean instance is the actual object created from that recipe.

So conceptually:

Bean definition:
  "I know how to create UserService."

Bean instance:
  new UserService(userRepository)

The ApplicationContext manages both the recipes and the actual objects.


6. Most Beans Are Singletons by Default

By default, Spring creates one shared instance of each bean per ApplicationContext.

That means this:

@Service
public class UserService {
}

usually results in one UserService object shared wherever it is injected.

So if three controllers need UserService, they all receive the same Spring-managed instance.

UserController  ─┐
AdminController ─┼──> same UserService bean
ReportController ┘

This is why Spring service beans should usually be stateless or carefully designed for thread safety.


7. You Usually Do Not Use ApplicationContext Directly

You can ask the context for a bean:

ApplicationContext context = ...;
UserService userService = context.getBean(UserService.class);

But in normal Spring application code, you usually should not do this.

Prefer dependency injection:

@Service
public class ReportService {

    private final UserService userService;

    public ReportService(UserService userService) {
        this.userService = userService;
    }
}

This is better because:

  • dependencies are explicit
  • the class is easier to test
  • the class is not tightly coupled to Spring’s container API
  • Spring can validate dependencies at startup

Use ApplicationContext#getBean() only when you truly need dynamic lookup.


8. ApplicationContext Is More Than a Bean Factory

Spring has a lower-level interface called BeanFactory.

A BeanFactory can create and manage beans.

ApplicationContext extends that idea and adds higher-level application features, such as:

  • event publishing
  • internationalization/message resolution
  • resource loading
  • environment and property access
  • integration with Spring AOP
  • web application support
  • lifecycle management

So you can think of it like this:

BeanFactory:
  Basic bean creation and dependency injection

ApplicationContext:
  BeanFactory + application-level services

In most real applications, you work with ApplicationContext, not directly with BeanFactory.


9. ApplicationContext and Dependency Injection

The most important job of the ApplicationContext is dependency injection.

Given this:

@Service
public class OrderService {

    private final PaymentService paymentService;
    private final OrderRepository orderRepository;

    public OrderService(
            PaymentService paymentService,
            OrderRepository orderRepository
    ) {
        this.paymentService = paymentService;
        this.orderRepository = orderRepository;
    }
}

Spring roughly does this:

1. See that OrderService is a bean
2. See that it needs PaymentService and OrderRepository
3. Find matching beans
4. Create those dependencies if needed
5. Call the OrderService constructor
6. Store the created OrderService bean in the context

You do not manually create the dependency graph. The ApplicationContext does.


10. ApplicationContext and Proxies

Sometimes the object you get from Spring is not the raw object you wrote.

It may be a proxy.

For example:

@Service
public class TransferService {

    @Transactional
    public void transferMoney() {
        // database work
    }
}

When @Transactional is involved, Spring may wrap TransferService in a proxy.

Conceptually:

Caller
  ↓
Transaction proxy
  ↓
Real TransferService

The proxy adds behavior around your method call:

begin transaction
call transferMoney()
commit transaction

or, if there is an error:

rollback transaction

This is why calls between Spring beans often need to go through the Spring-managed object, not through manually created objects.

The ApplicationContext is responsible for creating and managing those proxied beans.


11. ApplicationContext in a Web Application

In a Spring MVC web application, the ApplicationContext also contains web-related infrastructure.

For example:

Controller beans
Handler mappings
Request mappings
Message converters
Validation support
Exception handlers
View resolvers, if using server-side views

When a request arrives, Spring MVC uses beans from the context to decide:

GET /users/42

maps to something like:

@GetMapping("/users/{id}")
public UserDto findUser(@PathVariable Long id) {
    // ...
}

So in a web app, the context is not just managing services and repositories. It also supports request handling.


12. ApplicationContext in Spring Data JPA

With Spring Data JPA, repository interfaces are also managed through the context.

For example:

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

You do not create the implementation manually.

Spring Data creates a repository bean and registers it in the ApplicationContext.

Then you can inject it:

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

The context knows that UserRepository is a Spring-managed bean, even though you did not write the implementation class yourself.


13. Common Types of ApplicationContext

Different application types use different context implementations.

For annotation-based configuration, you may see:

AnnotationConfigApplicationContext

For web applications, Spring uses web-aware contexts.

In Spring Boot, you often do not create the context directly. You usually start the app with:

@SpringBootApplication
public class MyApplication {

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

SpringApplication.run(...) creates and starts the ApplicationContext for you.


14. A Small Manual Example

In a non-Boot or learning example, you might create the context manually:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        GreetingService greetingService =
                context.getBean(GreetingService.class);

        System.out.println(greetingService.greet("World"));
    }
}

But in real application classes, prefer injection over calling getBean().


15. Mental Model

A useful mental model is:

ApplicationContext = Spring's runtime registry and factory

It knows:
  - what beans exist
  - how to create them
  - how to connect them
  - how to configure them
  - when to initialize them
  - when to destroy them
  - whether to wrap them in proxies

Your code says:

I need a UserRepository.
I need a PaymentService.
This class is a controller.
This method should be transactional.
This property comes from configuration.

The ApplicationContext says:

I will create those objects,
wire them together,
apply the configuration,
wrap them if needed,
and make the application ready to run.

16. Practical Rules

When working with the ApplicationContext, remember these rules:

  1. Most application objects should be Spring beans.
  2. Use constructor injection for dependencies.
  3. Avoid manually calling new for services, repositories, and controllers.
  4. Avoid frequent direct use of ApplicationContext#getBean().
  5. Keep singleton beans stateless when possible.
  6. Remember that Spring may inject a proxy, not the raw class.
  7. If a bean is missing, check scanning, configuration, profiles, and conditional annotations.
  8. If multiple beans match, use @Primary or @Qualifier.

Bottom Line

The Spring ApplicationContext is the running Spring container.

It is responsible for:

  • discovering beans
  • creating beans
  • injecting dependencies
  • managing lifecycle
  • loading configuration
  • publishing events
  • supporting framework features
  • creating proxies for behavior like transactions

The shortest explanation is:

ApplicationContext is Spring’s runtime container: it creates, stores, wires, configures, and manages the objects that make up your application.

How do I use component scanning in Spring?

Component scanning is how Spring automatically finds your classes and registers them as beans.

Instead of manually creating every bean, you annotate classes with Spring stereotypes like:

@Component
@Service
@Repository
@Controller
@RestController

Then Spring scans selected packages, finds those classes, creates bean instances, and makes them available for dependency injection.


1. Basic Example

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public String getUserName() {
        return "Alice";
    }
}

Because UserService is annotated with @Service, Spring can discover it during component scanning.

You can inject it into another bean:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user")
    public String getUser() {
        return userService.getUserName();
    }
}

Spring automatically:

  1. finds UserService
  2. creates a UserService bean
  3. finds UserController
  4. creates a UserController bean
  5. injects UserService into UserController

2. Component Scanning in Spring Boot

In Spring Boot, component scanning is usually enabled automatically by @SpringBootApplication.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

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

@SpringBootApplication includes @ComponentScan.

By default, Spring Boot scans:

  • the package containing the main application class
  • all subpackages under it

For example:

com.example.demo
├── MyApplication.java
├── controller
│   └── UserController.java
├── service
│   └── UserService.java
└── repository
    └── UserRepository.java

If MyApplication is in com.example.demo, Spring scans:

com.example.demo
com.example.demo.controller
com.example.demo.service
com.example.demo.repository

This is the recommended structure.


3. Important Package Rule

Your main application class should usually be in the root package.

Good:

com.example.app
├── Application.java
├── user
│   ├── UserController.java
│   └── UserService.java
└── order
    ├── OrderController.java
    └── OrderService.java

Less ideal:

com.example.app.web
└── Application.java

com.example.app.service
└── UserService.java

If Application is inside com.example.app.web, Spring Boot scans com.example.app.web and its subpackages, but not sibling packages like com.example.app.service.


4. Manually Configure Component Scanning

If needed, you can specify packages explicitly with @ComponentScan.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

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

Or with multiple packages:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {
        "com.example.app.service",
        "com.example.app.repository",
        "com.example.shared"
})
public class AppConfig {
}

In Spring Boot, you can also place it on your main class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

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

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

5. Prefer basePackageClasses for Type Safety

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

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackageClasses = {
        UserService.class,
        SharedComponent.class
})
public class AppConfig {
}

Spring scans the packages where those classes are located.

This is safer than string package names because refactoring tools can update class references.


6. Common Component Annotations

@Component

Generic Spring-managed bean.

import org.springframework.stereotype.Component;

@Component
public class FileStorage {
}

Use this when no more specific annotation fits.


@Service

Business logic or service layer.

import org.springframework.stereotype.Service;

@Service
public class PaymentService {
}

@Repository

Persistence or data access layer.

import org.springframework.stereotype.Repository;

@Repository
public class JdbcUserRepository {
}

For Spring Data JPA, repository interfaces are often detected separately by repository scanning:

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

You usually do not need to add @Repository to Spring Data JPA interfaces.


@Controller

Spring MVC controller that usually returns views.

import org.springframework.stereotype.Controller;

@Controller
public class PageController {
}

@RestController

REST API controller.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HealthController {

    @GetMapping("/health")
    public String health() {
        return "OK";
    }
}

@RestController is equivalent to @Controller plus @ResponseBody.


7. Injecting Scanned Components

Once a class is discovered by component scanning, inject it using constructor injection.

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void placeOrder() {
        paymentService.charge();
    }
}

With Lombok:

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class OrderService {

    private final PaymentService paymentService;

    public void placeOrder() {
        paymentService.charge();
    }
}

8. Excluding Classes from Component Scanning

You can exclude specific classes or patterns.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
        basePackages = "com.example.app",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = ExperimentalService.class
        )
)
public class AppConfig {
}

You can also exclude by annotation:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
        basePackages = "com.example.app",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = DeprecatedComponent.class
        )
)
public class AppConfig {
}

9. Common Problems

Problem: Bean Not Found

Example error:

No qualifying bean of type 'com.example.UserService' available

Common causes:

  • the class is not annotated with @Component, @Service, etc.
  • the class is outside the scanned package
  • the class is abstract
  • the class has a failing constructor dependency
  • a required profile is not active
  • the bean is excluded by a scan filter

Problem: Controller Endpoint Not Working

Check that:

  • the controller has @Controller or @RestController
  • it is inside a scanned package
  • request mappings are correct
  • Spring MVC is enabled/configured
  • the application started without bean creation errors

Problem: Multiple Beans Found

If multiple scanned classes implement the same interface:

public interface PaymentProcessor {
    void process();
}
import org.springframework.stereotype.Service;

@Service
public class StripePaymentProcessor implements PaymentProcessor {

    @Override
    public void process() {
        // process with Stripe
    }
}
import org.springframework.stereotype.Service;

@Service
public class PaypalPaymentProcessor implements PaymentProcessor {

    @Override
    public void process() {
        // process with PayPal
    }
}

Injection by interface becomes ambiguous:

import org.springframework.stereotype.Service;

@Service
public class CheckoutService {

    public CheckoutService(PaymentProcessor paymentProcessor) {
    }
}

Fix it with @Primary:

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
@Primary
public class StripePaymentProcessor implements PaymentProcessor {

    @Override
    public void process() {
        // process with Stripe
    }
}

Or with @Qualifier:

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class CheckoutService {

    private final PaymentProcessor paymentProcessor;

    public CheckoutService(
            @Qualifier("paypalPaymentProcessor") PaymentProcessor paymentProcessor
    ) {
        this.paymentProcessor = paymentProcessor;
    }
}

10. Quick Rule of Thumb

For most Spring Boot applications:

  1. Put your main application class in the root package.
  2. Put controllers, services, repositories, and components in subpackages.
  3. Annotate classes with the right stereotype annotation.
  4. Use constructor injection.
  5. Avoid custom @ComponentScan unless you really need it.

A typical structure:

com.example.app
├── Application.java
├── controller
│   └── UserController.java
├── service
│   └── UserService.java
├── repository
│   └── UserRepository.java
└── config
    └── AppConfig.java

With this structure, Spring Boot component scanning usually works with no extra configuration.

How do I configure Spring using Java configuration?

Spring Java configuration lets you configure your application using Java classes instead of XML.

The main annotations are:

  • @Configuration — marks a class as a Spring configuration class
  • @Bean — declares a Spring bean manually
  • @ComponentScan — tells Spring where to find annotated components
  • @PropertySource — loads external properties
  • @Enable... annotations — enable specific Spring features, such as MVC, transactions, JPA, etc.

1. Create a configuration class

import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
}

@Configuration tells Spring that this class contains bean definitions and application setup.


2. Define beans manually with @Bean

Use @Bean when you want Spring to manage an object that you create yourself.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

Spring will create and manage the MyService instance.

By default, the bean name is the method name: myService.


3. Use component scanning

Instead of defining every bean manually, you can let Spring discover classes annotated with:

  • @Component
  • @Service
  • @Repository
  • @Controller
  • @RestController

Example:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

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

Then Spring can find beans like this:

import org.springframework.stereotype.Service;

@Service
public class MyService {

    public void doWork() {
        System.out.println("Working...");
    }
}

4. Inject dependencies through constructors

Java configuration works together with dependency injection.

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    public String findNameById(Long id) {
        return "Alice";
    }
}
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public String getUserName(Long id) {
        return userRepository.findNameById(id);
    }
}

If both classes are discovered by component scanning, Spring automatically injects UserRepository into UserService.


5. Bootstrapping Spring manually

For a non-Spring Boot application, you can start the Spring container like this:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        MyService myService = context.getBean(MyService.class);
        myService.doWork();
    }
}

6. Configure Spring MVC with Java configuration

For Spring MVC, use @EnableWebMvc and implement WebMvcConfigurer.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.example.app")
public class WebConfig implements WebMvcConfigurer {
}

Example controller:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring MVC";
    }
}

7. Load properties

You can load a properties file with @PropertySource.

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {
}

Then inject values with @Value:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppInfo {

    private final String appName;

    public AppInfo(@Value("${app.name}") String appName) {
        this.appName = appName;
    }
}

Example application.properties:

app.name=My Spring App

8. Enable transactions

If you use database transactions, enable them with @EnableTransactionManagement.

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class PersistenceConfig {
}

Then use @Transactional on services:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {

    @Transactional
    public void placeOrder() {
        // database operations
    }
}

Typical setup

A common Java configuration setup looks like this:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan("com.example.app")
@PropertySource("classpath:application.properties")
@EnableTransactionManagement
public class AppConfig {
}

For Spring MVC:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.example.app")
public class WebConfig implements WebMvcConfigurer {
}

Summary

To configure Spring using Java configuration:

  1. Create a class annotated with @Configuration.
  2. Add @ComponentScan to discover annotated classes.
  3. Use @Bean methods for manually created beans.
  4. Use constructor injection for dependencies.
  5. Add feature-specific annotations such as @EnableWebMvc, @EnableTransactionManagement, or JPA-related configuration as needed.

In most modern Spring applications, Java configuration plus component scanning replaces XML configuration almost entirely.