Skip to content
Spring Boot sb core 4 min read

Stereotype Annotations

Stereotype annotations are the markers that tell Spring’s container which classes to manage as beans. They are all built on @Component, so they behave identically during component scanning, but each one communicates a different architectural role. Using the right stereotype makes your code self-documenting and, in one case, adds real behavior.

What stereotypes do

When Spring boots up it performs component scanning: it walks the classpath looking for classes annotated with a stereotype and registers each as a bean in the ApplicationContext. From then on the container can autowire those beans wherever they are needed, as described in Dependency Injection & IoC.

A “stereotype” is simply a conventional role label. @Service does not give a class superpowers — it is @Component with a more specific name. The value is intent: a reader (and Spring tooling, and AOP pointcuts) can immediately see what layer a class belongs to.

The annotations at a glance

AnnotationUse it forAdds behavior?
@ComponentAny generic Spring-managed beanNo
@ServiceBusiness / domain logicNo (semantic only)
@RepositoryData-access objects (DAOs)Yes — exception translation
@ControllerMVC web controllers (return views)Routing via @RequestMapping
@RestControllerREST endpoints (return body)@Controller + @ResponseBody
@ConfigurationJava-based bean definitionsBean method proxying

Tip: When in doubt between @Component and @Service, prefer @Service for anything holding business logic. Reserve bare @Component for utility/support beans that do not fit another layer.

@Component — the base

@Component is the generic stereotype. Every other annotation here is meta-annotated with it.

@Component
public class GreetingFormatter {
    public String format(String name) {
        return "Hello, " + name + "!";
    }
}

@Service — business logic

@Service marks the layer that orchestrates business rules and coordinates repositories. Functionally it is identical to @Component, but it documents the role clearly.

@Service
public class OrderService {

    private final OrderRepository orderRepository;

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

    public Order place(Order order) {
        // business rules live here
        return orderRepository.save(order);
    }
}

@Repository — data access plus exception translation

@Repository marks data-access components, but unlike the others it is not purely semantic. Spring wraps @Repository beans with a post-processor that performs persistence exception translation: vendor-specific exceptions (such as a JPA PersistenceException or a raw JDBC SQLException) are converted into Spring’s consistent DataAccessException hierarchy.

@Repository
public class JdbcCustomerRepository {

    private final JdbcTemplate jdbcTemplate;

    public JdbcCustomerRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public int countAll() {
        // a SQLException here surfaces as a Spring DataAccessException
        return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM customer", Integer.class);
    }
}

Note: Spring Data JPA repository interfaces get exception translation automatically, so you rarely annotate those with @Repository yourself. The annotation matters most for hand-written DAOs using JdbcTemplate or an EntityManager.

@Controller and @RestController — web endpoints

@Controller is the web-layer stereotype. In classic MVC its methods return view names. @RestController is a convenience annotation that combines @Controller with @ResponseBody, so every method’s return value is serialized straight into the HTTP response body — the standard choice for JSON APIs.

@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public Order create(@RequestBody Order order) {
        return orderService.place(order);
    }
}

Output:

{
  "id": 42,
  "item": "Keyboard",
  "quantity": 2
}

@Configuration — declaring beans in code

@Configuration is a specialized @Component used for Java-based configuration. Its @Bean methods produce beans for types you cannot (or should not) annotate directly. Configuration classes have proxying semantics that ordinary components do not — see @Configuration & @Bean for the full story.

@Configuration
public class HttpConfig {

    @Bean
    public RestClient restClient() {
        return RestClient.create();
    }
}

Component scanning and @ComponentScan

Stereotypes only become beans if a scan reaches them. In a typical Spring Boot app the @SpringBootApplication annotation includes @ComponentScan, which scans the package of the main class and all sub-packages.

@SpringBootApplication // = @Configuration + @EnableAutoConfiguration + @ComponentScan
public class ShopApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShopApplication.class, args);
    }
}

This is why package layout matters: keep your code under the main application package so the default scan finds it. To scan elsewhere, declare the packages explicitly:

@SpringBootApplication
@ComponentScan(basePackages = {"com.shop", "com.shared.payments"})
public class ShopApplication { }

You can also narrow a scan with filters:

@ComponentScan(
    basePackages = "com.shop",
    excludeFilters = @ComponentScan.Filter(
        type = FilterType.ANNOTATION,
        classes = Deprecated.class))
public class ScanConfig { }

Warning: If a bean “cannot be found” or autowiring fails with NoSuchBeanDefinitionException, the most common cause is a class sitting outside the scanned package tree. Move it under the main package or add it to basePackages.

Custom stereotypes

Because stereotypes are just meta-annotations, you can compose your own to capture a project convention in one place:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
public @interface DomainService { }

A class annotated @DomainService is scanned exactly like a @Service. See Annotations for how meta-annotations work in plain Java.

Best Practices

  • Choose the most specific stereotype for the class’s role; reserve @Component for true utilities.
  • Use @Repository for hand-written DAOs to gain exception translation; Spring Data interfaces get it for free.
  • Prefer @RestController for JSON APIs and plain @Controller only when returning views.
  • Keep classes inside the main application package so the default @ComponentScan finds them.
  • Use excludeFilters/includeFilters instead of widening scans across unrelated packages.
Last updated June 13, 2026
Was this helpful?