Spring Annotations: The 2026 Essential Cheat Sheet
Master Spring annotations in 2026: from core stereotypes to new features like native resilience, virtual threads support, and null safety.
Spring 7, the foundation of Spring Boot 4, introduces several useful annotations that reduce boilerplate even further by adding native support for resilience, API versioning, and null-safety. This cheat sheet will guide you through the most important annotations and best practices for 2026.
Core Spring Stereotypes
These annotations remain the foundation of your Spring applications:
@Component: Generic bean. Use for internal utilities.
@Component
public class MyHelper { ... }@Service: Business logic layer. While@Serviceitself is a stereotype, Spring 7’s execution model is fully compatible with Virtual Threads, making service-layer code simpler and safer under high concurrency.
Dependency Injection & Configuration
@Autowired: Still exists, but Constructor Injection is now the absolute industry standard. Useful for tests. In Spring Boot 4, @Autowired is often omitted entirely on single-constructor classes.
@Bean: Registers a method-level bean.
@Configuration: Replaces XML-based configuration. Spring Boot 4 uses modular autoconfiguration for faster GraalVM native image startup.
Spring Boot 4 has moved toward a Modular Autoconfiguration model. Many old "starters" have been split into smaller, more focused modules to improve GraalVM native image startup times. For example, web, validation, and JSON support are now more decoupled, allowing smaller native images.
@ConfigurationProperties: Preferred over @Value. Works with Java Records for type-safe, immutable configuration.
``` java @ConfigurationProperties(prefix = "app") public record AppConfig(String name, int timeout) { }
## New in Spring 7: API Versioning :)
Spring 7 introduces first-class support for API versioning at the controller level, allowing multiple API versions to coexist cleanly.
@RestController @RequestMapping("/products") @ApiVersion("v1") public class ProductControllerV1 {
@GetMapping public List<ProductDto> getProducts() { return List.of(); } }
can coexist with:@RestController @RequestMapping("/products") @ApiVersion("v2") public class ProductControllerV2 {
@GetMapping public List<ProductV2Dto> getProducts() { return List.of(); } }
You can also use the version at method level:@GetMapping(path = "/{id}", version = "2.0+") // New version attribute public Product getProductV2(@PathVariable Long id) { return repository.findById(id).orElseThrow(); }
API versioning can be resolved via headers, media types, or URL strategies depending on configuration.
## New in Spring 7: Resilience & Concurrency
Spring 7 introduces first-class resilience annotations (either natively or via officially supported modules), reducing the need for third-party libraries in most cases.
- **`@Retryable`**: Automatically retries a failed operation with built-in backoff logic.
``` java
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 2000))
public void callExternalService() { ... }@Recover: Fallback method for exhausted retries:
``` java @Recover public void handleExternalServiceError(Exception e) { ... }
- **`@Timeout`**: Cuts off long-running operations declaratively.
- **`@ConcurrencyLimit`**: Essential for apps using Virtual Threads to prevent saturating external resources (like databases). Remember that with Virtual Threads there is no number of predefined threads.
Combine `@Retryable` + `@ConcurrencyLimit` to avoid saturating external services.
For the activation you need to add `@EnableResilientMethods` to your configuration class:
@Configuration @EnableResilientMethods // The switch for @Retryable and @ConcurrencyLimit public class ResilienceConfig { // Standard configuration class }
## JSpecify - Null safety in Spring 7 and Spring Boot 4
Spring 7 has fully embraced JSpecify for standardized null-safety across the Java ecosystem.
- **`@NonNull`**: Explicitly marks a parameter or return type as never null.
- **`@Nullable`**: Indicates that a null value is expected and must be handled.
- **`@NullMarked`**: Package-level default for non-nullable types.
You can use `@NullMarked` at the package level to make "Non-Null" the default for all classes in that package.
``` java
@NonNull
public String getUsername() { ... }Data & Persistence
With Spring 7 there is the support for JakartaEE 11 including Jakarta Data 1.0 and JPA 3.2.
With the update, Java Records can be used for immutable projections:
``` java public record ProductView( @Id Long id, String name, BigDecimal price ) {}
@Repository public interface ProductRepository {
Optional<ProductView> findById(Long id); }
- **`@Transactional`**: Maintain data integrity; place on the Service layer (class or method, better method-level) not Repository layer.
- **`@Entity`**: Marks a JPA entity. Many developers now use Java Records with Jakarta Data @Id for read-only DTOs.
## Quick Reference Table
| Annotation | Layer / Use Case | Notes |
| -------------------- | ------------------- | ----------------------------- |
| `@Component` | Generic bean | Utilities / internal classes |
| `@Service` | Business logic | Virtual Thread–friendly execution model |
| `@Repository` | Data access | Works with Jakarta Data |
| `@RestController` | REST APIs | Supports API Versioning |
| `@Retryable` | Resilience | Retry failed operations |
| `@ConcurrencyLimit` | Resource protection | Works with Virtual Threads |
| `@Timeout` | Resilience | Declares max execution time |
| `@Transactional` | Service layer | Ensures business atomicity |
| `@NonNull/@Nullable` | Null safety | Enforce null contracts |
## Code example
ProductService.java @Service @NullMarked // JSpecify default for the whole class public class ProductService {
private final ExternalApiClient client;
// injection using the constructor public ProductService(ExternalApiClient client) { this.client = client; }
@Transactional @Retryable(retryFor = {RemoteException.class}, maxAttempts = 3) @ConcurrencyLimit(10) // Protects the Virtual Thread pool public void processOrder(@NonNull String orderId) { client.call(orderId); } }