SpringBoot
Autowire
Dependency Injection
Java
Spring Framework

How to Autowire services in SpringBoot

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

Introduction

In Spring Boot, services are usually injected through Spring's dependency injection container rather than created with new. The normal workflow is to register a service as a bean, then inject it into controllers, other services, or configuration classes using constructor injection.

Define A Service Bean

Spring can only autowire classes it knows how to create. The most common way to register a service bean is to annotate it with @Service and place it in a package scanned by Spring Boot.

java
1package com.example.demo.service;
2
3import org.springframework.stereotype.Service;
4
5@Service
6public class GreetingService {
7    public String greet(String name) {
8        return "Hello, " + name;
9    }
10}

@Service is a specialization of @Component, so Spring will discover it automatically during component scanning.

Inject The Service Into Another Bean

The preferred pattern in modern Spring Boot is constructor injection. The dependency is required, explicit, and easy to test.

java
1package com.example.demo.web;
2
3import com.example.demo.service.GreetingService;
4import org.springframework.web.bind.annotation.GetMapping;
5import org.springframework.web.bind.annotation.RequestParam;
6import org.springframework.web.bind.annotation.RestController;
7
8@RestController
9public class GreetingController {
10    private final GreetingService greetingService;
11
12    public GreetingController(GreetingService greetingService) {
13        this.greetingService = greetingService;
14    }
15
16    @GetMapping("/greet")
17    public String greet(@RequestParam String name) {
18        return greetingService.greet(name);
19    }
20}

When Spring creates GreetingController, it sees the constructor parameter, finds a matching GreetingService bean, and injects it automatically.

When @Autowired Is Needed

For a single constructor, Spring Boot does not require the @Autowired annotation. The framework can infer that the constructor should be used.

java
1@Service
2public class ReportService {
3    private final GreetingService greetingService;
4
5    public ReportService(GreetingService greetingService) {
6        this.greetingService = greetingService;
7    }
8}

You still can use @Autowired, but for a single constructor it adds noise rather than value. It is more useful on setters, fields, or multiple constructors in older code styles.

Setter And Field Injection

Setter injection works for optional or replaceable dependencies.

java
1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.stereotype.Component;
3
4@Component
5public class AuditClient {
6    private GreetingService greetingService;
7
8    @Autowired
9    public void setGreetingService(GreetingService greetingService) {
10        this.greetingService = greetingService;
11    }
12}

Field injection is short, but it hides dependencies and makes testing harder.

java
1@Component
2public class BadExample {
3    @Autowired
4    private GreetingService greetingService;
5}

For most application code, constructor injection is the better default.

Multiple Service Implementations

If more than one bean matches the same interface, Spring needs help choosing one.

java
public interface NotificationService {
    void send(String message);
}
java
1@Service("emailNotificationService")
2public class EmailNotificationService implements NotificationService {
3    public void send(String message) {
4        System.out.println("Email: " + message);
5    }
6}
java
1@Service("smsNotificationService")
2public class SmsNotificationService implements NotificationService {
3    public void send(String message) {
4        System.out.println("SMS: " + message);
5    }
6}
java
1import org.springframework.beans.factory.annotation.Qualifier;
2import org.springframework.stereotype.Service;
3
4@Service
5public class OrderService {
6    private final NotificationService notificationService;
7
8    public OrderService(@Qualifier("emailNotificationService") NotificationService notificationService) {
9        this.notificationService = notificationService;
10    }
11}

Use @Qualifier when bean type alone is ambiguous.

Common Pitfalls

The most common problem is forgetting to make the service a Spring bean. If the class lacks @Service, @Component, @Bean, or another registration path, autowiring fails because Spring has nothing to inject.

Another issue is putting the class outside the application's component scan path. Spring Boot scans from the main application package downward by default.

A third mistake is using new GreetingService() manually inside application code. That bypasses Spring, so the object will not participate in dependency injection or bean lifecycle management.

Summary

  • Mark service classes with @Service so Spring can create them as beans.
  • Prefer constructor injection for required dependencies.
  • '@Autowired is optional for a single constructor in modern Spring.'
  • Use @Qualifier when multiple beans implement the same interface.
  • Avoid field injection and manual new when working inside Spring-managed code.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

All Rights Reserved.