Open any Spring Boot class and the first thing you see is annotations stacked above the declarations. To a beginner they look like decoration; to the framework they are instructions. Each one tells the container to register a bean, expose an endpoint, or inject a dependency. This tutorial groups the annotations you meet daily so you can read and write Spring Boot code without reaching for a reference every time.
Annotations are instructions to the container
Nothing in Spring Boot happens by convention over a bare class. A plain class is invisible to the
framework until an annotation marks it. @Service says "manage this as a bean". @GetMapping says
"route this HTTP path here". @Autowired says "supply this dependency". Learning the annotations is
therefore learning the vocabulary you use to talk to the container.
They fall into a few clear groups: application bootstrap, stereotypes that register beans, web annotations that handle HTTP, and injection annotations that wire beans together. We will take them group by group.
The bootstrap annotation
Every Spring Boot application has exactly one class carrying @SpringBootApplication:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ShopApp {
public static void main(String[] args) {
SpringApplication.run(ShopApp.class, args);
}
}
This single annotation is a shorthand for three:
@SpringBootConfiguration— marks the class as a source of bean definitions.@EnableAutoConfiguration— triggers auto-configuration based on the classpath.@ComponentScan— discovers your other annotated classes in this package and below.
That last point matters in practice: component scanning starts from the package of your main class, so keep it at the top of your package tree or classes in sibling packages will not be found.
Stereotype annotations that register beans
These four mark a class as a bean discovered by component scanning:
| Annotation | Intended role | Notable extra |
|---|---|---|
@Component |
Generic managed bean | The base for the others |
@Service |
Business-logic layer | Purely semantic |
@Repository |
Data-access layer | Adds exception translation |
@Controller |
Web layer (returns views) | Pairs with view templates |
Functionally, @Service and @Component do the same registration. The reason to use the specific
one is communication: a reader instantly knows a @Repository is a data-access class. @Repository
also earns its keep by translating vendor-specific database exceptions into Spring's consistent
DataAccessException hierarchy.
@Service
public class OrderService {
private final OrderRepository repository;
public OrderService(OrderRepository repository) { // constructor injection
this.repository = repository;
}
}
Pro tip: Reach for the most specific stereotype that fits. Using
@Componentfor everything works, but@Serviceand@Repositorydocument intent and, in the repository case, add real behaviour. Interviewers notice when a candidate uses them deliberately.
Web annotations for HTTP
The web layer is where annotations get dense. @RestController marks a class whose methods return
data directly, and the mapping annotations route requests to methods:
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}")
public String getOrder(@PathVariable Long id) {
return "Order " + id;
}
@GetMapping
public String listOrders(@RequestParam(defaultValue = "1") int page) {
return "Orders page " + page;
}
@PostMapping
public String createOrder(@RequestBody String payload) {
return "Created: " + payload;
}
}
Several distinctions here are exam favourites. @RestController equals @Controller plus
@ResponseBody, so you do not annotate each method. @PathVariable reads a value from the URL
path (/api/orders/42), while @RequestParam reads a query parameter (/api/orders?page=2).
@RequestBody deserialises the JSON request body into a Java object. These are the building blocks
covered in depth in building a REST API with Spring Boot.
Common mistake: Forgetting
@RequestBodyon a POST parameter. Without it, Spring tries to bind the object from request parameters instead of the JSON body, and your fields come back null. If a posted object is mysteriously empty, this is the first thing to check.
Injection annotations
Once beans exist, you wire them together. @Autowired is the explicit request for injection,
though on a single constructor it is optional:
@Service
public class NotificationService {
private final EmailClient emailClient;
// @Autowired optional here — one constructor
public NotificationService(EmailClient emailClient) {
this.emailClient = emailClient;
}
}
When two beans of the same type exist, @Qualifier names the one you want, and @Primary marks a
default. The full resolution flow — matching by type, then narrowing by qualifier — is covered in
the @Autowired tutorial. The key habit to form now
is preferring constructor injection, which keeps dependencies final and testable.
Configuration and bean-definition annotations
Beyond stereotypes, @Configuration classes let you define beans explicitly with @Bean methods —
useful for third-party classes you cannot annotate:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
A @Bean method's return value becomes a managed bean, named after the method. This is the manual
counterpart to component scanning: you use stereotypes for your own classes and @Bean for objects
you do not own.
Transaction and lifecycle annotations
Two more annotations appear constantly once your app touches a database. @Transactional wraps a
method in a database transaction — everything inside either commits together or rolls back together:
@Service
public class TransferService {
@Transactional
public void transfer(Long from, Long to, double amount) {
accounts.debit(from, amount);
accounts.credit(to, amount); // if this throws, the debit rolls back
}
}
If the credit throws an exception, Spring rolls the whole method back so the money is never lost.
The catch that surprises beginners is that @Transactional works through a proxy, so calling one
@Transactional method from another method in the same class does not start a new transaction —
the internal call bypasses the proxy. That single fact is a frequent interview trap.
The @PostConstruct and @PreDestroy lifecycle annotations round out the set, marking methods that
run after a bean is fully wired and just before it is destroyed. They belong to the bean lifecycle
rather than the web layer, but you place them with the same annotation-driven style as everything
else.
Meta-annotations: annotations made of annotations
The reason @SpringBootApplication and @RestController work is that Spring supports
meta-annotations — annotations composed of other annotations. @RestController is literally
defined as @Controller plus @ResponseBody. @SpringBootApplication bundles three annotations
into one.
This composition is not just Spring's trick; you can use it too. If several classes always carry the same group of annotations, you can define one custom annotation that combines them and apply that instead. Understanding this explains why decomposing a composite annotation is such a common interview question — it tests whether you know that these convenient single annotations are built from smaller, well-understood parts rather than being opaque keywords.
How they combine in a real class
The power comes from stacking. A controller might carry @RestController and @RequestMapping at
the class level, @GetMapping on methods, @PathVariable on parameters, and rely on constructor
injection for its service. Each annotation contributes one instruction, and the container assembles
them into working behaviour. Reading a Spring Boot class fluently is mostly a
matter of recognising which group each annotation belongs to.
Interview relevance
Annotation questions are guaranteed in Spring Boot interviews, and they escalate quickly. Start by
being able to decompose @SpringBootApplication into its three parts. Explain the difference
between @Controller and @RestController, and between @PathVariable and @RequestParam. Know
that the stereotypes are mostly semantic except for @Repository's exception translation. Practise
these with the dedicated Spring Boot annotations interview questions,
where a smooth, grouped answer marks you out from candidates who memorised a flat list.
Frequently Asked Questions
What does @SpringBootApplication actually do?
What is the difference between @Controller and @RestController?
Are @Component, @Service and @Repository technically different?
Do I always need @Autowired for injection?
What is the difference between @RequestParam and @PathVariable?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — Explore the Program

