Skip to content

Spring Stereotype Annotations, Dependency Injection, and IoC Container

All of these are stereotype annotations discovered through component scanning.

Annotation Layer Purpose
@Component Generic Any Spring bean
@Service Service Business logic
@Repository DAO Database operations
@Controller Web Handles HTTP requests
@RestController Web REST API controller (@Controller + @ResponseBody)
flowchart TD
A[Component Scan] --> B[@Component]
A --> C[@Service]
A --> D[@Repository]
A --> E[@Controller]
B --> F[ApplicationContext]
C --> F
D --> F
E --> F

@Repository translates persistence exceptions:

SQLException -> DataAccessException

Example:

@Service
public class UserService {}
@Repository
public class UserRepository {}
@Controller
public class UserController {}

Dependency Injection is a design pattern where Spring provides dependencies instead of classes creating them.

Without DI:

Service service = new Service();

With DI:

@Autowired
Service service;
  1. Constructor Injection
  2. Setter Injection
  3. Field Injection
sequenceDiagram
    participant Client
    participant Spring
    participant Service

    Client->>Spring: Request bean
    Spring->>Service: Create object
    Spring->>Service: Inject dependencies
    Spring-->>Client: Return fully initialized bean
Feature Constructor Injection Setter Injection
Injection Constructor Setter
Mandatory Dependency Yes No
Immutability Yes No
Testing Easier Harder
Recommended Yes Less preferred

Constructor injection:

@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}

Setter injection:

@Service
public class OrderService {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}

Recommendation: constructor injection is preferred because it guarantees mandatory dependencies and supports immutable classes — see also the field-injection best practice note.

The Inversion of Control (IoC) container is responsible for:

  • Creating objects
  • Injecting dependencies
  • Managing bean lifecycle
  • Configuring beans
  1. BeanFactory
    • Basic container
    • Lazy initialization
  2. ApplicationContext
    • Advanced container
    • Supports AOP, events, and internationalization

Example:

ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
Feature @Component @Bean
Annotation Type Class-level Method-level
Bean Creation Automatic Manual
Location On class Inside @Configuration
Control Less More
@Component
public class EmailService {
}
@Configuration
public class AppConfig {
@Bean
public EmailService emailService() {
return new EmailService();
}
}

Before annotation-based configuration became standard, beans were declared in XML:

<bean id="emailService" class="com.example.EmailService"/>

You’ll still encounter this in older Spring (non-Boot) codebases.

  • Third-party libraries
  • Classes that cannot be modified

Recommendation: use @Component for application classes discovered by component scanning, and @Bean when you need explicit control or are configuring third-party classes.

  • @Repository isn’t just a naming convention — it also translates SQLException into Spring’s DataAccessException hierarchy.
  • Constructor injection is preferred over setter/field injection: it guarantees mandatory dependencies, supports immutability, and is easier to test.
  • ApplicationContext is the container to use in practice; BeanFactory is the more basic, lazily-initialized base container.
  • Use @Component for your own classes and @Bean when you need explicit control or are wiring up a third-party class you can’t annotate.