Cheat Sheet

Spring Annotations

What each annotation does and the one thing that bites. Grouped by area; scan the table, then follow the link to the long-form page.

9
Groups
130+
Rows
Boot 3
Style
Index ยท Spring ยท SQL ยท Git ยท Docker/kubectl ยท Kafka/Rabbit CLI ยท Redis ยท Big-O
01
Chapter 1 - Core and stereotypes

Beans, Injection and Scanning

Spring Boot 3 / Spring Framework 6 style (jakarta.* imports). A "bean" is an object the container creates and wires for you.

AnnotationWhat it doesGotcha
@SpringBootApplicationShortcut for @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan on the main classScanning starts at the main class's package; beans in sibling packages above it are invisible
@ComponentGeneric stereotype: scanned and registered as a beanNeeds to be under a scanned package; a plain new object is not a bean
@Service@Component for business logic (no extra behaviour)Purely a label; it does not add transactions
@Repository@Component for data access; enables persistence exception translationTranslation only works through the proxy, so keep it on the class that talks to the store
@ControllerMVC controller; return values are view namesForgetting @ResponseBody on a JSON endpoint gives a "view not found" error
@RestController@Controller + @ResponseBody on every methodCannot return a view name; it returns text
@ConfigurationClass that declares beans with @Bean methodsFull mode (default) proxies the class so @Bean calls return the singleton; proxyBeanMethods = false turns that off
@BeanMethod return value becomes a bean; name defaults to the method nameStatic @Bean methods are needed for BeanFactoryPostProcessor types
@AutowiredInject by type (constructor, setter or field)Prefer constructor injection; a single constructor needs no annotation. Field injection hides dependencies and blocks final
@Qualifier("name")Pick one bean when several match the typeMatches bean name or qualifier value, not the class name
@PrimaryDefault choice when several beans match@Qualifier at the injection point wins over @Primary
@LazyCreate the bean (or inject a lazy proxy) on first useMoves startup failures to first request; mask for circular dependencies, not a fix
@Scope("prototype")New instance per injection or lookup (default is singleton)A prototype injected into a singleton is created once; use ObjectProvider to get fresh ones
@DependsOnForce bean creation orderOnly for hidden dependencies; real ones should be injected
@ImportPull in other @Configuration or selector classesUsed by @Enable* annotations; order of imports can matter for overrides
@ComponentScanSet packages to scanA second @ComponentScan overlapping the main one can register beans twice; prefer moving classes under the main package
@PostConstruct / @PreDestroyLifecycle callbacks after injection / before shutdown (jakarta.annotation)Run once per bean; they are not called for prototype destruction
@Order / @PrioritySort injected lists and ordered components (filters, aspects, listeners)Lower value runs first; it does not control bean creation order
@EventListenerMethod handles an application eventSynchronous by default and in the publisher's transaction
@TransactionalEventListenerHandle an event at a transaction phase (AFTER_COMMIT default)Silently ignored if there is no active transaction unless fallbackExecution = true
02
Chapter 2 - Configuration

Config, Properties, Conditions and Profiles

How values and conditional wiring get into beans. Boot loads application.properties or application.yml, profile variants, env vars and command-line args in a fixed precedence.

AnnotationWhat it doesGotcha
@Value("${key:default}")Inject one property, with optional default after the colonNo default means startup failure if the key is missing; #{...} is SpEL, ${...} is a placeholder
@ConfigurationProperties(prefix = "app")Bind a group of properties to a typed class or recordNeeds @EnableConfigurationProperties, @ConfigurationPropertiesScan or @Component to be registered
@EnableConfigurationProperties(X.class)Register a properties class as a beanNot needed if the class is already a component
@ConstructorBindingBind through the constructor (immutable properties)Boot 3: a single constructor of a record or class is enough; use the annotation only when there are several constructors
@Validated on properties classRun Bean Validation on bound propertiesNeeds spring-boot-starter-validation; put @Valid on nested objects
@PropertySource("classpath:x.properties")Add a properties file to the environmentDoes not support YAML; lower precedence than Boot's own files
@Profile("dev")Bean active only for the named profile!prod negates; @Profile on a @Configuration class gates all its beans
@ActiveProfiles("test")Select profiles in a test classReplaces, not adds to, spring.profiles.active for that test
@Conditional(MyCondition.class)Register bean only if a custom Condition matchesEvaluated while parsing configuration; do not depend on bean state
@ConditionalOnPropertyBean only if a property has a value (havingValue, matchIfMissing)Without matchIfMissing = true a missing property means "off"
@ConditionalOnClassBean only if a class is on the classpathUse the name attribute (string) on class-level conditions to avoid loading the class
@ConditionalOnMissingBeanBack off if the user defined a bean of that typeOnly reliable in auto-configuration; ordering in normal config is fragile
@ConditionalOnBeanBean only if another bean existsSame ordering fragility; mainly for auto-configuration
@ConditionalOnWebApplicationOnly in servlet or reactive web appsUse type to pick which
@ConditionalOnExpressionSpEL-based conditionHard to debug; prefer @ConditionalOnProperty
@RefreshScopeRe-create bean on config refresh (Spring Cloud)Not part of Spring Boot itself; needs Spring Cloud Context
03
Chapter 3 - Web (Spring MVC)

Controllers, Binding and Error Handling

Mapping annotations pick the handler; parameter annotations say where each argument comes from.

AnnotationWhat it doesGotcha
@RequestMappingMap URL, method, headers, media types (class or method level)Without method it matches every HTTP method
@GetMapping @PostMapping @PutMapping @PatchMapping @DeleteMappingShortcuts for @RequestMapping(method = ...)Class-level path + method-level path are concatenated
@PathVariableValue from {id} in the URLName must match the placeholder or be set explicitly; type mismatch gives 400
@RequestParamQuery or form parameterrequired = true by default; Optional or defaultValue relaxes it
@RequestBodyDeserialise the body (JSON by default) into an objectMalformed JSON gives 400 before your code runs; read once only
@RequestHeaderOne header valueRequired by default
@CookieValueOne cookie valueMissing cookie is a 400 unless required = false
@ModelAttributeBind form fields or query params to an objectNot for JSON bodies; used for form posts
@ResponseBodyWrite the return value to the response bodyAlready implied by @RestController
@ResponseStatus(HttpStatus.CREATED)Fixed status for a method or exception classIgnored if the method returns ResponseEntity with its own status
@CrossOriginAllow cross-origin calls on a handlerWith Spring Security the CORS config must also be enabled in the filter chain
@ControllerAdvice / @RestControllerAdviceGlobal handler for exceptions, binders and model attributesApplies to all controllers unless you narrow with basePackages or assignableTypes
@ExceptionHandler(X.class)Handle an exception type in a controller or adviceThe most specific type wins; return a ProblemDetail for RFC 9457 style bodies
@InitBinderCustomise data binding for a controllerRuns for every request to that controller
@ValidTrigger Bean Validation on an argument (jakarta.validation)Failure throws MethodArgumentNotValidException for bodies; nested objects need @Valid too
@ValidatedSpring variant: validation groups, and method validation on a classClass-level @Validated enables @NotNull etc. on method parameters through a proxy
@NotNull @NotBlank @Size @Min @Max @Email @PatternConstraint annotations on fields or parameters@NotNull allows empty string; @NotBlank is for strings only; @NotEmpty for collections
@RestClientTestSlice test for RestClient or RestTemplate codeCombine with MockRestServiceServer
04
Chapter 4 - Data and transactions

JPA, Spring Data and @Transactional

Transactions are applied by a proxy around the bean. That one fact explains most of the surprises below.

AnnotationWhat it doesGotcha
@TransactionalRun the method in a transaction (commit on return, roll back on exception)Only calls coming through the proxy count; see the self-invocation row
propagationHow to join or create (REQUIRED default, REQUIRES_NEW, NESTED, SUPPORTS, NOT_SUPPORTED, MANDATORY, NEVER)REQUIRES_NEW takes a second connection; deadlocks with the outer transaction on the same row
isolationIsolation level (DEFAULT uses the database default)Applies only when a new transaction starts (REQUIRED or REQUIRES_NEW)
readOnly = trueHint: no writes expected (can skip flush, route to replicas)A hint, not a guard; the driver or database may still allow writes
timeoutSeconds before the transaction is marked for rollbackApplies only to new transactions; not a statement timeout
rollbackFor / noRollbackForChoose which exceptions roll backDefault: RuntimeException and Error roll back, checked exceptions commit
Self-invocationthis.other() inside the same bean skips the proxyThe inner @Transactional has no effect; move it to another bean or use AspectJ mode
VisibilityClass-based proxies can handle protected and package-visible methods since 6.0Interface-based proxies need public methods declared on the interface; private is never advised
final class or methodCGLIB cannot subclass or override themAdvice (transactions, cache, async) silently does nothing
Checked exceptionsNot rolled back by defaultSet rollbackFor = Exception.class or the global rollbackOn option (Spring 6.2+)
@Entity @Table @IdMap a class to a table and mark the primary key (jakarta.persistence)Entities need a no-arg constructor (can be protected); avoid final
@GeneratedValueDatabase-generated key (IDENTITY, SEQUENCE, ...)IDENTITY disables JDBC batch inserts; Oracle and PostgreSQL work well with SEQUENCE
@Column @Enumerated(EnumType.STRING)Column details; store enums by nameDefault ORDINAL breaks when the enum order changes
@OneToMany @ManyToOne @ManyToManyRelationships; mappedBy marks the inverse side@OneToMany is lazy, @ManyToOne is eager by default; watch N+1 selects
@VersionOptimistic locking columnUpdate fails with OptimisticLockingFailureException on conflict; retry at the caller
@Query("...")Custom JPQL (or native with nativeQuery = true) on a repository methodModifying queries also need @Modifying and a transaction
@ModifyingMark an @Query as UPDATE or DELETEBypasses the persistence context; clearAutomatically = true avoids stale entities
@EntityGraphFetch associations in one query for a repository methodFixes N+1 but can multiply rows for collections
@Lock(LockModeType.PESSIMISTIC_WRITE)Lock rows read by a repository methodNeeds a transaction; lock timeouts are database specific
@EnableJpaRepositoriesTurn on repository scanningBoot does it for you; add it only for custom base packages
@EnableTransactionManagementTurn on @Transactional processingBoot auto-configures it; has mode and rollbackOn (6.2+) attributes
05
Chapter 5 - AOP, caching, scheduling, async

Proxy-Based Features

All of these work through proxies, so they share the same limits: no self-invocation, no private, no final.

AnnotationWhat it doesGotcha
@Aspect + @ComponentDeclare an aspect@Aspect alone does not register a bean
@Pointcut("execution(...)")Reusable pointcut expressionMatches only Spring beans, and only method execution
@Before @After @AfterReturning @AfterThrowingAdvice at fixed points@After runs on both outcomes (like finally)
@AroundWrap the call; you decide whether to call proceed()Forget proceed() and the target never runs; return its result
@EnableAspectJAutoProxyEnable @Aspect processingBoot enables it when spring-boot-starter-aop is present
@EnableCachingTurn on cache annotationsWithout it, @Cacheable is silently ignored
@Cacheable("name")Return a cached value, else call and storeKey defaults to the arguments; null results are cached unless unless = "#result == null"
@CachePutAlways run, then update the cacheDo not combine with @Cacheable on the same method
@CacheEvictRemove entries (allEntries = true clears the cache)beforeInvocation = false default: a failing method leaves the cache untouched
@CachingCombine several cache annotationsRarely needed; readability suffers
@EnableSchedulingTurn on @ScheduledWithout it, nothing runs and nothing complains
@Scheduled(fixedRate / fixedDelay / cron)Run periodicallyfixedRate can overlap if a run is slow with a multi-thread scheduler; default scheduler pool has one thread; runs on every instance
@EnableAsyncTurn on @AsyncWithout it, the method runs on the caller thread
@AsyncRun the method on an executor, return void or CompletableFutureExceptions from void methods go to the AsyncUncaughtExceptionHandler; the security and transaction contexts do not follow the thread
@Retryable / @RecoverRetry a method (needs the spring-retry library and @EnableRetry)Retry support is changing between Spring generations; check the reference for your Framework version before relying on the artifact
06
Chapter 6 - Security

Spring Security Annotations

Spring Security 6 style: a SecurityFilterChain bean for URL rules, annotations for method rules.

AnnotationWhat it doesGotcha
@EnableWebSecurityTurn on web security configurationBoot applies it automatically when Spring Security is on the classpath
@EnableMethodSecurityTurn on method security; replaces @EnableGlobalMethodSecurity@PreAuthorize family is on by default; @Secured needs securedEnabled = true, JSR-250 needs jsr250Enabled = true
@PreAuthorize("hasRole('ADMIN')")Check before the method runs (SpEL)hasRole adds the ROLE_ prefix, hasAuthority does not
@PostAuthorizeCheck after the method returns (can use returnObject)The method has already run, including side effects
@PreFilter / @PostFilterFilter collection arguments or resultsFilters in memory after loading everything; slow for big collections
@Secured("ROLE_X")Older role checkNo SpEL; must write the full ROLE_ name
@AuthenticationPrincipalInject the current principal into a controller methodType must match what your UserDetailsService returns
@WithMockUserFake an authenticated user in a testDoes not run your filters or JWT validation
07
Chapter 7 - Testing

Test Slices and Test Beans

@SpringBootTest loads everything; slices load only one layer and run faster.

AnnotationWhat it doesGotcha
@SpringBootTestLoad the full application contextDefault webEnvironment = MOCK starts no server; use RANDOM_PORT for real HTTP
@WebMvcTest(X.class)Only MVC beans: controllers, advice, filtersServices and repositories are not loaded; supply them with @MockitoBean. Boot 4 moved slices into per-technology modules (for example spring-boot-webmvc-test), so imports change when upgrading
@DataJpaTestJPA slice: entities, repositories, transaction rollback per testReplaces your DataSource with an embedded database unless you set @AutoConfigureTestDatabase(replace = NONE)
@JsonTestTest JSON serialisation onlyUses the auto-configured ObjectMapper
@MockitoBeanReplace or add a Mockito mock bean in the context (Spring Framework test annotation)Replaces @MockBean, which is deprecated since Boot 3.4; mocks skip AOP proxies, so @Transactional and @Cacheable do not apply to them
@MockitoSpyBeanWrap an existing bean in a Mockito spy; replaces @SpyBeanNeeds exactly one candidate bean; cannot spy on scoped proxies
@MockBean / @SpyBeanBoot's older equivalentsDeprecated since 3.4 in favour of the two Framework annotations above; not exact drop-in replacements
@TestConfigurationExtra beans for a test onlyNot picked up by component scanning of the main app when nested
@DynamicPropertySourceSet properties from a runtime value (Testcontainers port)Method must be static
@ServiceConnectionWire a Testcontainers container to auto-configuration without propertiesBoot 3.1+; works with supported container types only
@Sql("/data.sql")Run a script before a testRuns inside the test transaction unless configured otherwise
@DirtiesContextThrow away the cached context after the testVery slow when overused; each different config creates another cached context
@TestPropertySourceInline or file properties for a testHighest precedence among property sources
@AutoConfigureMockMvcAdd MockMvc to a @SpringBootTestNot needed with @WebMvcTest
08
Chapter 8 - Messaging listeners

Kafka and RabbitMQ

Listener annotations turn a method into a message consumer. Boot auto-configures the listener infrastructure when the client libraries are present.

AnnotationWhat it doesGotcha
@EnableKafkaProcess @KafkaListener (Boot auto-configures it)Needed only in non-Boot apps
@KafkaListener(topics = "t", groupId = "g")Consume records from a topicConsumers sharing a groupId split the partitions; concurrency above the partition count is wasted
@KafkaListener(topicPartitions = ...)Assign specific partitions and offsetsBypasses group rebalancing for those partitions
@RetryableTopicNon-blocking retry topics and a dead-letter topicChanges topic names and ordering guarantees
@KafkaHandlerMethod-level routing on a class-level @KafkaListenerOnly one isDefault handler allowed
@EnableRabbitProcess @RabbitListener (Boot auto-configures it)Needed only in non-Boot apps
@RabbitListener(queues = "q")Consume messages from a queueDefault acknowledge mode is automatic; an uncaught exception causes requeue and can loop forever without a retry or DLQ policy
@RabbitHandlerMethod-level routing on a class-level @RabbitListenerChosen by payload type
@SendToSend the return value to another destinationNeeds a reply template or address configured
09
Chapter 9 - Common mistakes

Spring Annotation Mistakes

โš  The ones that cost real time
  • **@Transactional on a method called from the same class.** No proxy, no transaction. Move the method to another bean.
  • **@Transactional on private, final or static methods.** Silently ignored. Same for @Async, @Cacheable, @Scheduled advice.
  • **Forgetting @EnableCaching, @EnableScheduling or @EnableAsync.** The annotation compiles and does nothing.
  • Expecting checked exceptions to roll back. They commit by default; set rollbackFor.
  • **Mixing @MockBean and @MockitoBean in one project.** Pick one; on Boot 3.4+ use @MockitoBean.
  • Field injection everywhere. Hides dependencies and makes unit tests need a container.
  • **@Value for a whole config group.** Use @ConfigurationProperties; it is typed and validated.
  • **@Scheduled on a clustered service.** It runs on every instance; add a lock (for example ShedLock) or run it on one node.
  • **@Async void methods that throw.** The caller never sees the error; return a CompletableFuture.
  • **javax.* imports on Boot 3.** Boot 3 uses jakarta.*; mixed imports cause confusing "no such bean" or binding errors.
10
Chapter 10 - Go deeper

Long-form pages and what was checked

TopicPage
Core container, beans and wiringSpring Core, Beans
Configuration and propertiesConfiguration
REST controllers, validation, errorsREST API, Validation & Errors
Transactions and JPATransactions, Data JPA
AOP, caching, resilienceAOP, Caching & Resilience
Security and JWTSecurity, JWT & OAuth2
TestingTesting
Kafka and RabbitMQ with SpringKafka with Spring, RabbitMQ
Version note

Checked on 2026-10-31: @Transactional defaults, attributes, visibility rules and the 6.2 rollbackOn option against the Spring Framework reference (data-access/transaction/declarative/annotations); @EnableMethodSecurity replacing @EnableGlobalMethodSecurity and the securedEnabled / jsr250Enabled opt-ins against the Spring Security reference; @MockBean / @SpyBean deprecation in Boot 3.4 against the Boot 3.4 release notes; @MockitoBean behaviour (AOP proxies skipped, singleton conversion, REPLACE_OR_CREATE default) and the @SpringBootTest default MOCK environment against the current Boot and Framework testing docs. Not re-checked line by line: the Spring Kafka and Spring AMQP listener rows and the JPA mapping rows, which follow the long-form pages.