Spring Boot Tutorial
Spring Boot Annotations Reference
Spring Boot code is built from annotations: they declare components, inject dependencies, map URLs, bind configuration, manage transactions and configure tests. Knowing what each common annotation does — and which package it lives in — makes reading any Spring Boot project much easier.
This lesson is a categorised reference of the annotations you will use most, each with a short explanation and a combined example that uses them together.
Application and Configuration
These define the application and its beans:
@SpringBootApplication— combines@SpringBootConfiguration,@EnableAutoConfigurationand@ComponentScan.@Configuration— a class that declares beans with@Beanmethods.@Bean— registers the method's return value as a Spring bean.@ComponentScan— packages to scan for components.@Import— imports other configuration classes.@Profile("dev")— only active in the given profile.@Conditional...—@ConditionalOnProperty,@ConditionalOnMissingBean,@ConditionalOnClassfor conditional beans.@ConfigurationProperties(prefix = "app")and@EnableConfigurationProperties— type-safe configuration binding.@Value("${app.name}")— inject a single property value.
Stereotypes and Dependency Injection
Stereotypes mark classes for component scanning and describe their role:
@Component— a generic Spring-managed component.@Service— business logic layer.@Repository— persistence layer; also translates database exceptions to Spring's DataAccessException.@Controller/@RestController— web layer; RestController adds @ResponseBody to every method.@Autowired— inject a dependency (optional on a single constructor, which is the recommended style).@Qualifier("name")and@Primary— choose between several beans of the same type.@Scope("prototype"),@Lazy,@PostConstruct,@PreDestroy— scope, lazy creation and lifecycle callbacks.
Web (Spring MVC)
Request handling annotations:
@RequestMapping,@GetMapping,@PostMapping,@PutMapping,@PatchMapping,@DeleteMapping.@PathVariable,@RequestParam,@RequestBody,@RequestHeader,@CookieValue,@ModelAttribute.@ResponseStatus— fixed HTTP status for a method or exception class.@RestControllerAdvice/@ControllerAdviceand@ExceptionHandler— global error handling.@CrossOrigin— per-controller CORS.@Valid/@Validated— trigger Bean Validation.
Data, Transactions and Other Features
Persistence and cross-cutting annotations:
@Entity,@Table,@Id,@GeneratedValue,@Column,@OneToMany,@ManyToOne— JPA mapping.@Query,@Modifying,@EntityGraph— Spring Data repository methods.@Transactional— transaction boundaries.@EnableCaching/@Cacheable,@EnableAsync/@Async,@EnableScheduling/@Scheduled,@EnableResilientMethods/@Retryable.@EventListener,@TransactionalEventListener— application events.@Aspect,@Before,@Around... — AOP.@EnableMethodSecurity,@PreAuthorize— method security.
Testing
Test annotations from Spring Boot and Spring Test:
@SpringBootTest— full application context.@WebMvcTest,@DataJpaTest,@RestClientTest,@JsonTest— slice tests.@MockitoBean,@MockitoSpyBean— replace beans with mocks or spies.@AutoConfigureMockMvc,@AutoConfigureRestTestClient— test clients.@ServiceConnection,@Testcontainers,@Container— Testcontainers integration.@TestConfiguration,@ActiveProfiles,@DynamicPropertySource,@WithMockUser.
Examples
One small feature using the most common annotations together
@SpringBootApplication
@EnableConfigurationProperties(ShopProperties.class)
@EnableCaching
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
}
@ConfigurationProperties(prefix = "shop")
record ShopProperties(String currency, int maxCartItems) {}
@Entity
class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id;
@Column(nullable = false) String name;
BigDecimal price;
}
@Repository
interface ProductRepository extends JpaRepository<Product, Long> {
@Query("select p from Product p where p.price <= :max order by p.price")
List<Product> cheaperThan(BigDecimal max);
}
@Service
class ProductService {
private final ProductRepository repo;
private final ShopProperties props;
ProductService(ProductRepository repo, ShopProperties props) { // constructor injection
this.repo = repo;
this.props = props;
}
@Cacheable("cheapProducts")
@Transactional(readOnly = true)
public List<Product> cheaperThan(BigDecimal max) {
return repo.cheaperThan(max);
}
}
@RestController
@RequestMapping("/api/products")
class ProductController {
private final ProductService service;
ProductController(ProductService service) {
this.service = service;
}
@GetMapping
List<Product> cheap(@RequestParam(defaultValue = "1000") BigDecimal max) {
return service.cheaperThan(max);
}
}
@RestControllerAdvice
class ApiErrors {
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
ProblemDetail badRequest(IllegalArgumentException ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, ex.getMessage());
}
}
GET /api/products?max=800
[{"id":3,"name":"Cap","price":499.00},{"id":2,"name":"Tee","price":799.00}]
(second identical request is served from the "cheapProducts" cache)
Choosing between beans with @Primary and @Qualifier
interface PaymentGateway { String pay(BigDecimal amount); }
@Component
@Primary
class RazorpayGateway implements PaymentGateway {
public String pay(BigDecimal amount) { return "razorpay:" + amount; }
}
@Component("stripeGateway")
class StripeGateway implements PaymentGateway {
public String pay(BigDecimal amount) { return "stripe:" + amount; }
}
@Service
class CheckoutService {
private final PaymentGateway defaultGateway;
private final PaymentGateway internationalGateway;
CheckoutService(PaymentGateway defaultGateway,
@Qualifier("stripeGateway") PaymentGateway internationalGateway) {
this.defaultGateway = defaultGateway; // @Primary wins
this.internationalGateway = internationalGateway;
}
}
defaultGateway.pay(100) -> razorpay:100
internationalGateway.pay(100) -> stripe:100
Common Mistakes
- Using field injection with @Autowired everywhere instead of constructor injection.
- Putting @Transactional or @Cacheable on private methods, where proxies cannot apply them.
- Confusing @Controller (returns view names) with @RestController (returns response bodies).
- Adding @EnableWebMvc or @EnableAutoConfiguration again in a Boot app that already has @SpringBootApplication.
- Mixing javax.* annotations from old tutorials with jakarta.* in Spring Boot 3/4 projects.
Key Points to Remember
- @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan.
- Stereotypes (@Component, @Service, @Repository, @RestController) mark beans by layer.
- Web annotations map requests and bind data; @RestControllerAdvice handles errors globally.
- Feature annotations (@Transactional, @Cacheable, @Async, @Scheduled) work through proxies.
- Test annotations provide full-context, slice, mock and container-based tests.
Practice the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Use your local JDK or project IDE for these examples. Codelab currently runs Python and HTML/CSS/JavaScript; framework examples may need project dependencies.