Fundamentals of Spring IoC/DI, bean scopes, AOP proxies, Spring MVC, Boot auto-configuration, JdbcTemplate, JPA/Hibernate entity lifecycle and mappings, transactions, Spring Data, validation, testing and actuator.
Overview chapter covering the fundamentals interviewers expect from every Java backend engineer. Deep production scenarios live in the separate Spring track.
Theory
Q1
What are Inversion of Control and Dependency Injection?
basic
IoC means the framework, not your code, controls object creation and wiring. DI is the main IoC technique: a class declares its dependencies and the container supplies them.
Benefits: loose coupling, easy substitution of collaborators in tests, centralized lifecycle management.
The container is an ApplicationContext that reads configuration (annotations, Java config, XML) and builds a graph of beans.
⚠ Follow-up traps
Is IoC the same as DI? No. DI is one way to achieve IoC; service locator and template-method callbacks are others.
Does DI require a framework? No, passing collaborators through a constructor by hand is DI.
#ioc#di#fundamentals
Q2
What is the difference between BeanFactory and ApplicationContext?
basic
BeanFactory is the minimal container interface (lazy bean creation, DI). ApplicationContext extends it and adds event publishing, MessageSource i18n, resource loading, environment/profile support, AOP integration and eager singleton initialization.
Application code almost always uses ApplicationContext; BeanFactory is an internal building block.
⚠ Follow-up traps
Are singletons created lazily in an ApplicationContext? No, by default they are created eagerly at refresh, which surfaces wiring errors at startup.
Which one does Spring Boot create? An ApplicationContext implementation such as AnnotationConfigServletWebServerApplicationContext.
#ioc#applicationcontext#beanfactory
Q3
What are the ways to inject dependencies, and which is preferred?
basic
Constructor, setter and field injection. Constructor injection is preferred.
Constructor: dependencies are final, object is never half-built, trivial to unit test without Spring, circular dependencies fail fast.
Setter: for optional or reconfigurable dependencies.
Field (@Autowired on a field): hides dependencies, cannot be final, needs reflection in tests.
Since Spring 4.3 a single constructor needs no @Autowired.
@Servicepublic class OrderService { private final OrderRepository repo; public OrderService(OrderRepository repo) { this.repo = repo; }}
⚠ Follow-up traps
Does field injection work on private fields? Yes, via reflection, which is exactly why it is discouraged.
With two constructors, which is used? The one annotated @Autowired; otherwise the default no-arg constructor is required.
#di#constructor-injection#autowired
Q4
How does Spring resolve which bean to inject when several match?
basic
Autowiring is by type first. If multiple candidates remain, Spring uses @Primary, then @Qualifier, then falls back to matching the parameter/field name with the bean name. If still ambiguous it throws NoUniqueBeanDefinitionException.
@Qualifier("name") is explicit at the injection point and wins over @Primary.
Injecting List<T> or Map<String,T> collects all beans of the type.
⚠ Follow-up traps
Does @Primary override @Qualifier? No, @Qualifier is more specific and wins.
What if no bean matches?NoSuchBeanDefinitionException, unless @Autowired(required=false), Optional<T> or @Nullable is used.
#autowired#qualifier#primary
Q5
What is the difference between @Component, @Service, @Repository and @Controller?
basic
All are stereotype annotations meta-annotated with @Component, so component scanning registers them as beans. The specialization conveys the layer and adds behavior in two cases.
@Repository: enables persistence exception translation to DataAccessException through a post-processor.
@Controller/@RestController: detected by Spring MVC as request handlers.
@Service: purely semantic.
⚠ Follow-up traps
Does @Service add transactions? No, @Transactional must be applied separately.
What does @RestController combine?@Controller plus @ResponseBody.
#stereotypes#component-scan
Q6
@Configuration with @Bean versus @Component scanning: when to use which?
intermediate
Use component scanning for your own classes; use @Bean methods in @Configuration classes for third-party classes or when construction needs logic.
@Configuration classes are CGLIB-proxied (full mode) so that calling one @Bean method from another returns the same singleton instead of creating a new object.
@Configuration(proxyBeanMethods = false) (lite mode) skips the proxy for faster startup when no inter-bean method calls exist; Boot's own auto-configurations use it.
⚠ Follow-up traps
In a plain @Component, does calling a @Bean method return the singleton? No, it is lite mode and each call creates a new instance.
Can @Configuration classes be final? Not in proxy mode, since CGLIB must subclass them.
#configuration#bean#java-config
Q7
What are the bean scopes in Spring?
basic
singleton (default, one per container), prototype (new instance per request for the bean), and in web contexts request, session, application and websocket. Custom scopes can be registered.
Singleton is per container, not per JVM and not like the GoF pattern.
Spring does not manage the full lifecycle of prototypes: destroy callbacks are not called.
⚠ Follow-up traps
Are singleton beans thread-safe automatically? No. They are shared, so mutable state must be avoided or protected.
Is the default scope singleton per class? Per bean definition; two definitions of one class give two singletons.
#scopes#singleton#prototype
Q8
How do you inject a prototype bean into a singleton?
intermediate
Injecting directly resolves the prototype once at singleton creation, so you get the same instance forever. Fix it by injecting an ObjectProvider<T> (call getObject()), a lookup method (@Lookup), or a scoped proxy.
@Componentclass Runner { private final ObjectProvider<Task> tasks; Runner(ObjectProvider<Task> tasks) { this.tasks = tasks; } void run() { tasks.getObject().execute(); } // new Task each call}
⚠ Follow-up traps
Does @Scope(proxyMode = TARGET_CLASS) also work? Yes, a proxy resolves a fresh target per method call.
Same issue for request scope? Yes, a request-scoped bean in a singleton needs a scoped proxy or provider.
#scopes#prototype#scoped-proxy
Q9
Describe the Spring bean lifecycle.
intermediate
Instantiate -> populate properties (DI) -> *Aware callbacks -> BeanPostProcessor.postProcessBeforeInitialization -> @PostConstruct -> InitializingBean.afterPropertiesSet -> custom init-method -> postProcessAfterInitialization (where AOP proxies are created) -> bean in use -> on shutdown @PreDestroy -> DisposableBean.destroy -> custom destroy method.
@PostConstruct/@PreDestroy are in jakarta.annotation since Spring 6 / Boot 3 (javax before).
⚠ Follow-up traps
Are dependencies available in the constructor of a field-injected bean? No, fields are injected after construction.
Where is the AOP proxy created? In a BeanPostProcessor after initialization, so @PostConstruct runs on the raw target.
#lifecycle#postconstruct#beanpostprocessor
Q10
How does Spring handle circular dependencies?
intermediate
For singleton beans with setter/field injection Spring exposes early references via a three-level cache and resolves the cycle. With constructor injection it cannot, and throws BeanCurrentlyInCreationException.
Since Spring Boot 2.6 circular references are prohibited by default (spring.main.allow-circular-references=false).
Real fix: redesign (extract a third bean, use events), or break with @Lazy on one injection point.
⚠ Follow-up traps
Do prototype cycles work? No, Spring does not cache prototypes, so it fails.
Does @Lazy remove the cycle? It injects a lazy proxy, deferring resolution, but the design smell remains.
#circular-dependency#di
Q11
What does @SpringBootApplication do?
basic
It is a composite of @SpringBootConfiguration (a @Configuration), @EnableAutoConfiguration and @ComponentScan rooted at the annotated class's package.
Beans outside the main class's package tree are not scanned unless scanBasePackages is set.
⚠ Follow-up traps
Why put the main class in a root package? Component scan covers that package and sub-packages only.
Can you exclude an auto-configuration? Yes, @SpringBootApplication(exclude = X.class) or spring.autoconfigure.exclude.
#spring-boot#auto-configuration
Q12
How does Spring Boot auto-configuration work?
intermediate
@EnableAutoConfiguration imports classes listed in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Boot 2.7+/3.x; formerly spring.factories). Each is a @Configuration guarded by conditions such as @ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty.
Because of @ConditionalOnMissingBean, your own bean always backs off the default.
Run with --debug or use the actuator conditions endpoint to see the condition evaluation report.
⚠ Follow-up traps
Are auto-configurations applied before or after user config? After, which is what lets @ConditionalOnMissingBean see your beans.
Is spring.factories still used for auto-config in Boot 3? No, the .imports file replaced it.
#auto-configuration#conditional
Q13
What are Spring Boot starters?
basic
Starters are curated dependency descriptors (for example spring-boot-starter-web, -data-jpa, -test, -validation, -actuator) that pull a consistent set of libraries. They contain no code of note; the auto-configuration module does the wiring.
Version alignment comes from the spring-boot-dependencies BOM through spring-boot-starter-parent or the dependency-management plugin.
⚠ Follow-up traps
Why do you not specify versions for starters? The BOM manages them.
Which server does starter-web embed? Tomcat by default; exclude it and add starter-jetty or starter-undertow to switch.
#starters#dependency-management
Q14
How do profiles work?
basic
Profiles group beans and properties per environment. Activate with spring.profiles.active=prod, an env var SPRING_PROFILES_ACTIVE, or --spring.profiles.active. Beans use @Profile("dev"); properties live in application-dev.yml and override the base file.
A profile expression like @Profile("!prod") or "dev & local" is supported.
Boot 2.4+ also supports spring.config.activate.on-profile inside multi-document YAML.
⚠ Follow-up traps
If no profile is active, which runs? The default profile.
Is spring.profiles still valid in a profile-specific document? No, it was replaced by spring.config.activate.on-profile in 2.4.
#profiles#configuration
Q15
What is the precedence order of Spring Boot configuration sources?
intermediate
Higher wins: command-line args, SPRING_APPLICATION_JSON, OS environment variables, profile-specific files outside the jar, profile-specific files inside the jar, application.properties/yml outside, then inside the jar, @PropertySource, and finally defaults.
Env var MY_APP_DB_URL maps to my.app.db.url through relaxed binding.
This is how a container overrides a packaged default without rebuilding.
⚠ Follow-up traps
application.properties and application.yml both present? Both load; .properties wins on conflicts.
Does @PropertySource support YAML? Not by default; it needs a custom factory.
#externalized-config#properties
Q16
@Value versus @ConfigurationProperties?
intermediate
@Value("${key:default}") injects a single value with SpEL support. @ConfigurationProperties(prefix="app") binds a hierarchy to a typed bean with relaxed binding, validation and IDE metadata. Prefer the latter for groups of settings.
@ConfigurationProperties(prefix = "app.mail")@Validatedpublic record MailProps(@NotBlank String host, @Min(1) int port) {}
Register with @EnableConfigurationProperties or @ConfigurationPropertiesScan; records use constructor binding in Boot 3.
⚠ Follow-up traps
Does @Value support relaxed binding? Not fully; use the exact key.
Does a @Validated properties class fail at startup? Yes, binding errors stop the app, which is desirable.
Aspect: class holding the concern. Advice: the action (@Before, @After, @AfterReturning, @AfterThrowing, @Around).
Join point: a point in execution (in Spring AOP always a method execution). Pointcut: expression selecting join points.
Weaving: linking aspects to targets; Spring does it at runtime via proxies.
⚠ Follow-up traps
Can Spring AOP intercept field access or constructors? No, only public/protected method calls on Spring beans; use AspectJ for more.
Which advice can change the return value or skip the call? Only @Around.
#aop#aspect#pointcut
Q18
How does Spring AOP create proxies?
intermediate
If the bean implements an interface, a JDK dynamic proxy may be used; otherwise a CGLIB subclass proxy. Spring Boot defaults to CGLIB (spring.aop.proxy-target-class=true) even when interfaces exist.
CGLIB cannot proxy final classes or final/private methods.
Callers get the proxy; the proxy runs advice then delegates to the target.
⚠ Follow-up traps
Why inject by interface works with JDK proxies but by class fails? The JDK proxy is not a subtype of the concrete class; Boot's CGLIB default avoids this.
Does a final method with @Transactional work? No, advice is silently skipped.
#aop#proxy#cglib
Q19
Why does self-invocation bypass @Transactional or other AOP advice?
intermediate
Advice lives in the proxy. A call this.method() inside the target goes straight to the raw object, never through the proxy, so no advice runs.
Fixes: move the method to another bean, inject the proxy (self-injection with @Lazy), use AopContext.currentProxy() with exposeProxy=true, or use AspectJ weaving.
⚠ Follow-up traps
Does it matter if the called method is public? No, the issue is the call path, not visibility.
Does @Async have the same limitation? Yes.
#aop#self-invocation#proxy
Q20
Describe the Spring MVC request flow.
basic
The request hits DispatcherServlet (front controller) -> HandlerMapping finds the handler and interceptors -> HandlerAdapter invokes the controller method, resolving arguments (@PathVariable, @RequestBody) via HandlerMethodArgumentResolvers -> return value handled by HttpMessageConverter (for @ResponseBody) or a ViewResolver + view -> response.
Exceptions go to HandlerExceptionResolvers such as @ExceptionHandler/@ControllerAdvice.
Servlet filters run before DispatcherServlet; HandlerInterceptors run after mapping.
⚠ Follow-up traps
Filter vs interceptor? Filter is a servlet-container concept wrapping everything; interceptor is Spring MVC, knows the handler and cannot see the raw stream before binding.
How is JSON produced? Jackson via MappingJackson2HttpMessageConverter.
#spring-mvc#dispatcherservlet
Q21
@RequestParam, @PathVariable and @RequestBody: differences?
basic
@PathVariable binds a URI template segment (/users/{id}), @RequestParam a query/form parameter, @RequestBody deserializes the body via a message converter.
@RequestParam is required by default; use required=false or defaultValue.
Using a missing required param yields HTTP 400.
⚠ Follow-up traps
Can there be two @RequestBody parameters? No, the body stream is consumed once.
What does @RequestParam do with form posts? It binds application/x-www-form-urlencoded fields too.
#spring-mvc#binding
Q22
How do you handle exceptions globally in Spring MVC?
intermediate
Use @RestControllerAdvice with @ExceptionHandler methods mapping exceptions to responses. Spring 6 / Boot 3 supports RFC 7807 ProblemDetail (spring.mvc.problemdetails.enabled=true) and ResponseEntityExceptionHandler.
What does @ResponseStatus and ResponseEntity give you?
basic
@ResponseStatus fixes a status on a method or exception class. ResponseEntity<T> lets you set status, headers and body dynamically per call.
Default status for @ResponseBody return is 200; returning void with @ResponseStatus(NO_CONTENT) gives 204.
⚠ Follow-up traps
Can @ResponseStatus vary at runtime? No, use ResponseEntity for that.
Returning null from a @ResponseBody method? Empty body with 200.
#spring-mvc#responseentity
Q24
What is the difference between Spring MVC and WebFlux?
intermediate
MVC is servlet-based and blocking, one thread per request. WebFlux is non-blocking, built on Reactor (Mono/Flux) over Netty or servlet 3.1+ async, using few event-loop threads.
WebFlux helps with high concurrency and streaming, but only if the whole chain (including DB drivers) is non-blocking.
Java 21 virtual threads (spring.threads.virtual.enabled=true, Boot 3.2) let MVC scale blocking code with much less rewrite.
⚠ Follow-up traps
Is WebFlux faster for CRUD over JDBC? No, blocking JDBC on event loops hurts.
Can you use RestClient or WebClient?WebClient works in both; RestClient (6.1) is the sync alternative.
#webflux#spring-mvc#reactive
Q25
What is JdbcTemplate and what does it solve?
basic
JdbcTemplate removes JDBC boilerplate: it acquires/releases connections, prepares statements, iterates ResultSets, and translates SQLException into the unchecked DataAccessException hierarchy.
List<User> users = jdbc.query( "select id, name from users where active = ?", (rs, i) -> new User(rs.getLong("id"), rs.getString("name")), true);
⚠ Follow-up traps
Is it thread-safe? Yes once configured; share one instance.
Does it prevent SQL injection? Only if you use ? placeholders, not string concatenation.
#jdbc#jdbctemplate
Q26
JdbcTemplate versus NamedParameterJdbcTemplate versus JdbcClient?
intermediate
NamedParameterJdbcTemplate uses :name parameters, avoiding positional errors and allowing IN (:ids) with collections. JdbcClient (Spring 6.1) is a fluent facade over both.
jdbcClient.sql("select * from users where status = :s") .param("s", "ACTIVE") .query(User.class).list();
SimpleJdbcInsert and KeyHolder help fetch generated keys.
⚠ Follow-up traps
Can plain JdbcTemplate bind a list to IN (?)? No, you must expand placeholders yourself; the named variant does it.
How do you batch?batchUpdate with a BatchPreparedStatementSetter or a list of args.
#jdbc#namedparameterjdbctemplate#jdbcclient
Q27
What is the difference between JPA, Hibernate and Spring Data JPA?
basic
JPA (Jakarta Persistence) is a specification of interfaces and annotations. Hibernate is the most common implementation. Spring Data JPA is a layer on top that generates repository implementations and uses JPA (so Hibernate) underneath.
Boot 3 uses Hibernate 6 and the jakarta.persistence package (was javax.persistence).
⚠ Follow-up traps
Can you use JPA without Hibernate? Yes, with EclipseLink or OpenJPA.
Does Spring Data JPA replace the EntityManager? No, it wraps it; you can still inject the EntityManager.
#jpa#hibernate#spring-data
Q28
Explain the JPA entity states.
basic
Transient/new: not associated with a persistence context, no row.
Managed/persistent: attached to a session; changes are tracked and flushed.
Detached: was managed, its session closed or cleared.
Is an entity with an id set always detached? No; a new object with a manually assigned id is still transient until persisted.
Does persist on a detached entity work? It throws PersistentObjectException/EntityExistsException; use merge.
#entity-lifecycle#persistence-context
Q29
What is the persistence context (first-level cache)?
basic
The persistence context is the per-EntityManager/Session identity map. It guarantees one instance per entity id, caches loaded entities, and tracks changes for dirty checking. It is always on and cannot be disabled.
em.find twice with the same id hits the database once.
JPQL queries still execute SQL, but returned rows resolve to already-managed instances.
⚠ Follow-up traps
Does the first-level cache share across threads or requests? No, it is scoped to one session (typically one transaction).
Does a JPQL query hit the cache? It always runs SQL; only find by id short-circuits.
#first-level-cache#session#persistence-context
Q30
How does dirty checking and flushing work?
intermediate
On load Hibernate stores a snapshot of each entity's state. At flush it compares current state to the snapshot and issues UPDATEs for differences, so no explicit save is needed for a managed entity.
Flush happens at commit, before a JPQL/HQL query that touches affected tables (FlushMode.AUTO), or on explicit flush().
Flush sends SQL; commit makes it durable.
⚠ Follow-up traps
Does repo.save(managedEntity) add anything? No-op for a managed entity; the update happens anyway.
Does flush equal commit? No; flushed changes can still roll back.
#dirty-checking#flush#hibernate
Q31
What is the difference between persist, merge, save and saveOrUpdate?
intermediate
persist makes a new entity managed (same instance) and returns void. merge copies state of a detached/new object onto a managed instance and returns that instance; the argument stays unmanaged. Hibernate's save/saveOrUpdate are legacy native APIs (deprecated in 6, removed later). Spring Data's save calls persist if isNew() else merge.
isNew() is true when the id is null (or the version is null for a wrapper-typed @Version).
⚠ Follow-up traps
After merge(x), is x managed? No, only the returned copy.
save with an assigned id that is never null? Treated as existing, so it does merge (an extra SELECT); implement Persistable to fix.
#persist#merge#spring-data
Q32
Explain the main JPA relationship mappings.
basic
@OneToOne, @OneToMany, @ManyToOne, @ManyToMany. The owning side holds the foreign key; the inverse side uses mappedBy.
Best practice: prefer a bidirectional @OneToMany with @ManyToOne as owner, or only unidirectional @ManyToOne.
@ManyToMany hides a join table; model an explicit join entity when it needs extra columns.
@JoinColumn names the FK column.
⚠ Follow-up traps
Who owns the relationship with mappedBy? The other side, the one without mappedBy.
Is a unidirectional @OneToMany efficient? It uses a join table or extra UPDATEs; avoid unless needed.
#mappings#onetomany#manytomany
Q33
What are the fetch types and their defaults?
basic
LAZY loads the association on first access via a proxy or lazy collection; EAGER loads it with the owner. Defaults: @ManyToOne and @OneToOne are EAGER; @OneToMany and @ManyToMany are LAZY.
Best practice: set @ManyToOne(fetch = LAZY) and fetch what you need per query (JOIN FETCH, entity graphs).
⚠ Follow-up traps
Is LAZY a guarantee? It is a hint for to-one associations without bytecode enhancement; collections are reliably lazy.
Why is EAGER risky? It cascades into N+1 selects and loads data you may not need.
#fetch-type#lazy#eager
Q34
What is the N+1 select problem and how do you fix it?
intermediate
Loading N parents then touching a lazy association on each issues 1 + N queries. Fix by fetching together: JOIN FETCH, @EntityGraph, @BatchSize/default_batch_fetch_size, or a DTO projection.
@Query("select o from Order o join fetch o.items where o.status = :s")List<Order> findWithItems(@Param("s") Status s);
⚠ Follow-up traps
Can you JOIN FETCH two bags? No, MultipleBagFetchException; fetch one and batch the other, or use Set.
Does join fetch with pagination work? Hibernate paginates in memory (warning HHH000104); avoid for collections.
#n-plus-one#performance#join-fetch
Q35
What is LazyInitializationException?
intermediate
It is thrown when a lazy association or proxy is accessed after its session closed. Fix by loading what you need inside the transaction (fetch join, entity graph, DTO), not by switching to EAGER globally.
spring.jpa.open-in-view (default true in Boot) keeps the session open through the web layer and hides the problem, at the cost of holding a connection longer.
⚠ Follow-up traps
Does @Transactional on the controller fix it? It stretches the transaction over the web layer; better to map to DTOs in the service.
Should you disable open-in-view? Many teams do for production, accepting explicit fetching.
#lazy#session#exceptions
Q36
What are cascade types and orphanRemoval?
intermediate
cascade propagates entity operations (PERSIST, MERGE, REMOVE, REFRESH, DETACH, ALL) from parent to child. orphanRemoval = true deletes a child removed from the parent's collection.
Use only for true parent-owned children (composition), never CascadeType.ALL on @ManyToOne or shared entities.
⚠ Follow-up traps
Does REMOVE on @ManyToMany make sense? Rarely; it may delete shared entities.
Difference between REMOVE cascade and orphanRemoval? Cascade acts when the parent is removed; orphan removal acts when a child is detached from the collection.
#cascade#orphan-removal
Q37
How do @GeneratedValue strategies differ?
intermediate
IDENTITY uses auto-increment columns: simple, but the insert must happen immediately to know the id, disabling JDBC insert batching. SEQUENCE fetches ids from a DB sequence (with allocationSize pooling), allowing batching. AUTO picks per dialect (sequence on PostgreSQL/Oracle in Hibernate 6). TABLE is slow and rarely used. UUID is supported directly.
⚠ Follow-up traps
Why does IDENTITY block batching? Hibernate needs the generated key right after each insert.
Mismatch between allocationSize and sequence increment? Duplicate or skipped ids; they must match (default 50).
#id-generation#sequence#identity
Q38
What does @Version do?
intermediate
@Version enables optimistic locking. Hibernate adds where version = ? to updates and increments it; if no row matches, it throws OptimisticLockException (ObjectOptimisticLockingFailureException in Spring).
No DB lock is held, so it suits low-contention updates; callers handle the exception with a retry or an error to the user.
Pessimistic alternative: LockModeType.PESSIMISTIC_WRITE (select ... for update).
⚠ Follow-up traps
Is the version bumped on every field change? On any flushed update of that entity.
Do bulk JPQL updates bump the version? Not unless you write versioned in HQL or do it manually.
#optimistic-locking#version
Q39
What is JPQL and how does it differ from native SQL?
basic
JPQL queries entities and their fields rather than tables and columns, is database independent, and is translated to SQL by the provider. Native queries run raw SQL when you need vendor features.
TypedQuery<User> q = em.createQuery( "select u from User u where u.email = :email", User.class);q.setParameter("email", email);
⚠ Follow-up traps
Is JPQL case-sensitive? Keywords are not; entity and field names are.
Do native queries return managed entities? Yes if you map to an entity type; otherwise tuples/DTOs.
#jpql#hql#native-query
Q40
What is the Criteria API and when is it useful?
intermediate
The Criteria API builds queries programmatically and type-safely, ideal for dynamic filters where predicates are added conditionally.
CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<User> cq = cb.createQuery(User.class);Root<User> u = cq.from(User.class);cq.select(u).where(cb.equal(u.get("status"), "ACTIVE"));List<User> r = em.createQuery(cq).getResultList();
Spring Data's Specification wraps Criteria; Querydsl is a popular alternative.
⚠ Follow-up traps
Is Criteria faster than JPQL? No, same execution; it is only about composition.
What is the metamodel for? Generated User_ classes avoid string field names.
#criteria#dynamic-queries#specification
Q41
How do Spring Data JPA repositories work?
basic
You declare an interface extending JpaRepository<T, ID> (or CrudRepository, PagingAndSortingRepository). Spring creates a JDK proxy at startup backed by SimpleJpaRepository, supporting CRUD, paging, sorting, derived queries, @Query and projections.
Is the derived query validated? Yes at startup; a wrong property name fails the context.
Are repository methods transactional? Reads in SimpleJpaRepository are readOnly, writes @Transactional.
#spring-data#repository
Q42
How do paging and sorting work in Spring Data?
intermediate
Pass a Pageable (PageRequest.of(page, size, Sort)) and return Page<T> (runs an extra count query), Slice<T> (fetches size+1 to know if there is a next page, no count) or List<T>.
Page numbers are zero-based.
Offset paging degrades on deep pages; keyset (seek) pagination or Window (3.1+) scales better.
⚠ Follow-up traps
Why is Page sometimes slow? The count query on large tables.
Does sorting accept arbitrary client strings safely? No, validate property names to avoid errors and information leaks.
#pageable#spring-data#pagination
Q43
What does @Transactional do and what are its defaults?
basic
It wraps a method in a transaction through an AOP proxy: begin before, commit on success, rollback on failure. Defaults: propagation REQUIRED, isolation DEFAULT (database default), readOnly=false, no timeout.
Rolls back on unchecked exceptions (RuntimeException, Error) but commits on checked exceptions unless rollbackFor is set.
Applies only to calls entering through the Spring proxy, on public methods (for proxy-based AOP).
⚠ Follow-up traps
Does a checked exception roll back? No, by default it commits.
Class-level vs method-level? Method-level overrides class-level.
#transactional#transactions
Q44
Explain transaction propagation levels.
intermediate
REQUIRED (default): join existing or create new.
REQUIRES_NEW: suspend current, always run in a new independent transaction.
SUPPORTS: join if present, else non-transactional.
MANDATORY: must have one, else exception.
NOT_SUPPORTED: suspend and run without one.
NEVER: fail if one exists.
NESTED: savepoint inside the outer transaction (JDBC only; JPA/Hibernate transaction manager does not support it).
⚠ Follow-up traps
Does REQUIRES_NEW use the same connection? No, a second connection, so pool exhaustion is a risk.
If an inner REQUIRED method throws and the caller catches it, can the outer commit? No, the shared transaction is already marked rollback-only (UnexpectedRollbackException).
#propagation#transactions
Q45
What are isolation levels and which anomalies do they prevent?
PostgreSQL and Oracle default to READ_COMMITTED; MySQL InnoDB to REPEATABLE_READ.
Set per method with @Transactional(isolation = ...).
⚠ Follow-up traps
Does PostgreSQL honor READ_UNCOMMITTED? It treats it as READ_COMMITTED.
What does readOnly=true do? A hint: Hibernate skips dirty checking/flush and some drivers route to replicas; it is not a security guarantee.
#isolation#transactions
Q46
How does Bean Validation work in Spring?
basic
Add spring-boot-starter-validation (Hibernate Validator). Annotate fields with constraints (@NotNull, @NotBlank, @Size, @Email, @Min) and trigger with @Valid/@Validated on a @RequestBody parameter. Failures raise MethodArgumentNotValidException (400).
public record SignUp(@NotBlank String name, @Email String email) {}@PostMapping("/users")ResponseEntity<Void> create(@Valid @RequestBody SignUp req) { ... }
⚠ Follow-up traps
@NotNull vs @NotEmpty vs @NotBlank? Not null; not null and length > 0; not null and contains a non-whitespace character.
Is validation applied to nested objects automatically? Only if the nested field carries @Valid.
#validation#bean-validation
Q47
@Valid versus @Validated?
intermediate
@Valid is the standard Jakarta annotation and cascades into nested objects. @Validated is Spring's variant that supports validation groups and, at class level, enables method-level validation of parameters on any bean via a proxy.
Method validation of @PathVariable/@RequestParam constraints needs @Validated on the controller (Spring 6.1 built-in handler validation makes this implicit).
Violations there throw ConstraintViolationException (or HandlerMethodValidationException in 6.1).
⚠ Follow-up traps
Which supports groups?@Validated.
Same exception type for body and param violations? Not in older versions: MethodArgumentNotValidException vs ConstraintViolationException.
#validation#validated#groups
Q48
What testing slices and annotations does Spring Boot provide?
basic
@SpringBootTest loads the full context (add webEnvironment for a real or random port). Slices load only a layer: @WebMvcTest (controllers + MVC infrastructure, with MockMvc), @DataJpaTest (JPA + embedded DB, transactional rollback per test), @JsonTest, @RestClientTest, @DataJdbcTest.
@MockBean (deprecated in Boot 3.4 for @MockitoBean) replaces a bean with a mock in the context.
⚠ Follow-up traps
Are @Service beans loaded by @WebMvcTest? No; mock them.
Does @DataJpaTest use the real DB? It replaces it with an embedded one unless @AutoConfigureTestDatabase(replace = NONE).
#testing#springboottest#slices
Q49
How do you unit-test a service versus integration-test with a real database?
intermediate
Unit-test services with plain JUnit 5 and Mockito (@ExtendWith(MockitoExtension.class)), no Spring context, relying on constructor injection. For persistence, use @DataJpaTest against Testcontainers with the production database engine (Boot 3.1+ @ServiceConnection wires the URL automatically).
Embedded H2 can hide dialect differences (JSON, locking, sequences).
⚠ Follow-up traps
Is the Spring context cached across tests? Yes, by configuration key, so different @MockBean sets create new contexts and slow the suite.
Does @Transactional on a test roll back? Yes by default, which can hide commit-time issues.
#testing#mockito#testcontainers
Q50
What is Spring Boot Actuator?
basic
Actuator adds production endpoints for health, metrics, info, environment, beans, mappings, loggers, thread dumps and more, via spring-boot-starter-actuator. Over HTTP only health is exposed by default; others need management.endpoints.web.exposure.include.
Metrics use Micrometer and can export to Prometheus and others.
⚠ Follow-up traps
Why secure env and heapdump? They can leak secrets and memory contents.
Can you move management to a separate port? Yes, management.server.port.
#actuator#monitoring
Q51
How do health indicators, liveness and readiness probes work?
intermediate
/actuator/health aggregates HealthIndicator beans (db, disk, custom). On Kubernetes, Boot exposes /actuator/health/liveness and /readiness groups (auto-enabled in a detected K8s environment or via management.endpoint.health.probes.enabled=true).
Readiness should reflect ability to take traffic; liveness should only fail when a restart helps.
Do not include downstream dependencies in liveness, or an outage restarts every pod.
⚠ Follow-up traps
Overall status when one indicator is DOWN? DOWN (HTTP 503), by default status order.
How to add a custom indicator? Implement HealthIndicator as a bean; name derives from the class name minus the suffix.
#actuator#health#kubernetes
Q52
What is Hibernate's second-level cache and query cache?
advanced
The second-level cache is a SessionFactory-wide cache of entity state shared across sessions, off by default, enabled with a JCache/Ehcache/Infinispan provider and @Cacheable plus a cache concurrency strategy. The query cache stores id lists for queries and depends on the L2 cache.
Good for read-mostly reference data; invalidated per table on writes.
Not cluster-coherent without a distributed provider.
⚠ Follow-up traps
Is it enabled by default? No.
Does it cache collections automatically? Only if the collection itself is annotated for caching.
#second-level-cache#caching#hibernate
Scenarios
Q53
A @Transactional method calls another @Transactional method in the same class. Does the second get its own transaction?
intermediate
No. The inner call is this.inner(), bypassing the proxy, so its @Transactional(propagation = REQUIRES_NEW) is ignored and it runs in the caller's transaction (or none, if the caller is not transactional).
Move inner into another bean, or inject the proxy of the bean itself.
⚠ Follow-up traps
Will a rollback in inner roll back outer? Yes, since they are the same transaction.
Will it compile and start fine? Yes, the failure is silent.
#transactional#self-invocation
Q54
A service method throws a checked IOException annotated @Transactional. Is the data saved?
basic
Yes, it is committed. Default rollback rules cover only RuntimeException and Error. Use @Transactional(rollbackFor = IOException.class) (or Exception.class) to roll back.
⚠ Follow-up traps
What about an unchecked exception that is caught and swallowed inside the method? The proxy never sees it, so it commits.
Does EJB behave the same? Yes, similar rule: application exceptions (checked) do not roll back by default.
#transactional#rollback
Q55
@Transactional is put on a private method. What happens?
basic
Nothing: proxy-based AOP only intercepts calls through the proxy, and private methods are not proxied (CGLIB cannot override them; the JDK proxy sees only interface methods). No transaction starts and no error is raised. Since Spring 6, protected/package-private methods work with class-based proxies, but private still does not.
⚠ Follow-up traps
Does AspectJ mode fix it? Yes, weaving into bytecode can advise private methods.
Does final on a public method have the same effect? Yes, CGLIB cannot override it.
#transactional#proxy
Q56
Two inner calls: audit log must persist even if the main transaction rolls back. How?
intermediate
Put the audit write in a separate bean method annotated @Transactional(propagation = REQUIRES_NEW) and call it through the proxy. It commits independently when it returns.
What if it fails and throws? It rolls back its own transaction and, if propagated, also marks the outer one for rollback.
Cost? A second connection; the pool can deadlock if all connections are held by outer transactions waiting for inner ones.
#propagation#requires-new#audit
Q57
A controller accesses order.getItems() after the service returns and gets LazyInitializationException. With open-in-view on, it works. Why?
intermediate
OpenEntityManagerInViewInterceptor binds one EntityManager to the whole web request, so the session stays open after the service transaction ends and lazy loads still succeed (each triggers an auto-commit query). With it off, the session closes at the end of the @Transactional method.
Fix properly: fetch the items in the service (join fetch, @EntityGraph) or map to a DTO there.
⚠ Follow-up traps
Does Boot warn about it? Yes, a startup warning about spring.jpa.open-in-view being enabled by default.
Is lazy loading in the view inside a transaction? No, it runs in auto-commit mode.
#lazy#open-in-view
Q58
A list endpoint issues 101 SQL statements for 100 orders. Diagnose and fix.
intermediate
Classic N+1: one query for orders plus one per order for a lazy (or eager) association. Confirm with spring.jpa.show-sql or Hibernate statistics, then use @EntityGraph(attributePaths = "customer") or join fetch, or set spring.jpa.properties.hibernate.default_batch_fetch_size=50 to turn N into N/50 IN queries.
Does making the association LAZY solve it? It makes it appear only when accessed; the N+1 stays.
Does a DTO projection avoid it? Yes, one query selecting only the needed columns.
#n-plus-one#entity-graph
Q59
You fetch-join a collection and use pagination. What does Hibernate do?
advanced
Hibernate cannot apply LIMIT to a joined row set (it would cut parent rows), so it fetches all rows, paginates in memory and logs HHH000104: firstResult/maxResults specified with collection fetch; applying in memory. This can blow up memory.
Workaround: paginate parent ids in one query, then fetch the collections for those ids in a second query, or use batch fetching.
⚠ Follow-up traps
Does it happen for @ManyToOne fetch joins? No, to-one joins do not multiply rows.
Does @EntityGraph on a collection have the same issue? Yes.
#pagination#join-fetch#hibernate
Q60
You change a managed entity's field inside a @Transactional method and never call save. Is the DB updated?
basic
Yes. The entity is managed, so dirty checking at flush/commit detects the change and issues an UPDATE. Outside a transaction (or on a detached entity), nothing is written.
⚠ Follow-up traps
Would readOnly = true update it? Typically not; Hibernate sets flush mode to MANUAL and skips dirty checking.
What if you load it with a projection or DTO? Not managed, so no update.
#dirty-checking#transactional
Q61
What is printed?
intermediate
@Transactionalvoid demo(Long id) { User a = em.find(User.class, id); User b = em.find(User.class, id); System.out.println(a == b);}
Prints true, with only one SELECT. The second find is served from the persistence context identity map. In two separate transactions (two sessions) you get two SELECTs and different instances.
⚠ Follow-up traps
Would a JPQL select u from User u where u.id = :id between them issue SQL? Yes, but the returned instance is still the same managed object.
Does em.clear() change it? The next find re-queries and returns a new instance.
#first-level-cache#find
Q62
A JPQL query runs after an unflushed change. Is the change visible?
advanced
With FlushModeType.AUTO (default), Hibernate flushes pending changes before executing a query that touches the affected tables, so the query sees them. Native queries on Hibernate with JPA flush everything under JPA bootstrapping, but may not under native Session API unless synchronized.
With COMMIT mode, the query does not see pending changes.
⚠ Follow-up traps
Do bulk @Modifying updates see the persistence context? They bypass it; stale managed entities remain unless you clearAutomatically = true.
Does flush commit? No.
#flush-mode#jpql
Q63
After a @Modifying update query, a find returns the old value. Why?
advanced
Bulk JPQL updates execute directly in the database and do not update entities already loaded in the persistence context; subsequent find returns the cached stale instance.
@Modifying(clearAutomatically = true, flushAutomatically = true)@Query("update User u set u.status = 'INACTIVE' where u.lastLogin < :d")int deactivate(@Param("d") Instant d);
⚠ Follow-up traps
Are lifecycle callbacks and @Version triggered? No, bulk operations skip them.
Is @Modifying without a transaction OK? No, it needs a transaction (TransactionRequiredException).
#modifying#persistence-context#bulk-update
Q64
Why does saveAll of 10,000 entities with IDENTITY ids run slowly?
advanced
IDENTITY forces each insert to execute immediately to fetch the key, so Hibernate silently disables JDBC insert batching. Switch to SEQUENCE with allocationSize matching the sequence increment and set hibernate.jdbc.batch_size=50 (plus order_inserts=true). Also clear/flush periodically to bound the persistence context.
⚠ Follow-up traps
Does MySQL have sequences? No (MariaDB does); there you stay with IDENTITY or use JDBC batch inserts.
Does reWriteBatchedInserts matter? For PostgreSQL JDBC it rewrites into multi-row inserts and boosts throughput.
#batching#identity#performance
Q65
Two users edit the same record at the same time. How do you prevent lost updates?
intermediate
Add a @Version column. The second commit's update ... where id=? and version=? matches zero rows and Hibernate throws OptimisticLockException. Handle it by returning 409 or retrying.
@Entityclass Account { @Id Long id; @Version long version; BigDecimal balance;}
⚠ Follow-up traps
High-contention hot rows? Use pessimistic locking or an atomic SQL update.
Should the client send the version back? Yes in REST (ETag/If-Match or version field), otherwise the check only covers a single transaction.
#optimistic-locking#concurrency
Q66
A bidirectional OneToMany serialized with Jackson causes StackOverflowError. Why and how to fix?
intermediate
Parent serializes children, each child serializes the parent, forever. Fix by returning DTOs from controllers (best), or use @JsonIgnore, @JsonManagedReference/@JsonBackReference, or @JsonIdentityInfo.
Serializing entities also risks triggering lazy loads or exposing internal fields.
⚠ Follow-up traps
Does @ToString or hashCode from Lombok cause the same loop? Yes; exclude the back reference.
Is @JsonIgnore on a lazy collection safe? It avoids loading it, which is why it is often used.
#jackson#bidirectional#dto
Q67
An entity uses Lombok @Data and a lazy collection. What breaks?
advanced
@Data generates equals/hashCode/toString over all fields including relations: lazy collections get initialized (or throw LazyInitializationException), cycles recurse, and a mutable generated id or fields change hashCode while the entity sits in a HashSet.
Use @Getter/@Setter, base equals on a business key, or on the id with a constant hashCode pattern and null-id handling.
⚠ Follow-up traps
Should entities be final or records? No; Hibernate needs to proxy and mutate them.
Is a proxy getClass() equal to the entity class? No, so equals must use instanceof/Hibernate.getClass.
#equals-hashcode#lombok#entities
Q68
getById/getReference versus findById: what is the difference?
intermediate
findById hits the DB immediately and returns the entity or empty. getReferenceById returns a lazy proxy without a query; the SELECT happens on first property access, throwing EntityNotFoundException if absent. Use it to set an FK without loading the row.
Accessing the proxy after the session closes?LazyInitializationException.
Does the proxy's getId() trigger a load? Not with property access on the identifier in Hibernate, when accessed through the getter.
#proxy#getreference#findbyid
Q69
What happens in this circular constructor injection under Boot 3?
basic
@Service class A { A(B b) {} }@Service class B { B(A a) {} }
The context fails to start with BeanCurrentlyInCreationException / UnsatisfiedDependencyException describing the cycle. Even with setter injection, Boot 2.6+ refuses cycles by default.
Refactor so the dependency goes one way (extract shared logic to C) or publish an event.
⚠ Follow-up traps
Quick unsafe workaround?@Lazy on one parameter, or spring.main.allow-circular-references=true.
Does the error appear at the first request? No, at startup for singletons.
#circular-dependency#startup
Q70
You inject a prototype-scoped bean into a singleton and always get the same object. Why?
intermediate
The singleton's dependencies are resolved once at its creation, so the prototype is instantiated one time. Use ObjectProvider<T>, @Lookup, or @Scope(value="prototype", proxyMode=TARGET_CLASS) so each use gets a fresh instance.
⚠ Follow-up traps
Are prototype @PreDestroy methods called? No, the container does not track them.
Is ApplicationContext.getBean inside the method acceptable? It works but couples code to the container.
#prototype#scopes
Q71
Two beans of type PaymentGateway exist and one service injects it. What error occurs and how do you resolve it?
basic
NoUniqueBeanDefinitionException: expected single matching bean but found 2. Resolve with @Primary on the default, @Qualifier("stripe") at the injection point, naming the parameter after the bean, or injecting Map<String, PaymentGateway> for strategy selection.
Does parameter-name matching require -parameters? Spring Boot's Maven/Gradle plugins compile with it by default.
Can you inject by bean name only?@Resource(name=...) does name-first matching.
#qualifier#primary#autowired
Q72
@ConditionalOnMissingBean bean is not replaced by your own bean. What could be wrong?
advanced
Typical causes: your bean has a different type than the one checked (for example you declare the implementation with another return type), it is defined in a configuration not scanned, or it is registered after the auto-config is evaluated. Use --debug or /actuator/conditions to see why the condition matched.
Declare the @Bean with the same type or interface the auto-config tests for.
⚠ Follow-up traps
Does the return type of @Bean method matter? Yes, conditions are evaluated against the declared return type.
Are user beans processed before auto-config? Yes, auto-configs are deferred imports.
#auto-configuration#conditional#debugging
Q73
Property app.timeout is set in application.yml, application-prod.yml and as env var APP_TIMEOUT. Which wins in prod?
intermediate
The environment variable APP_TIMEOUT wins; it outranks packaged config files, including application-prod.yml. Between the two files, application-prod.yml overrides application.yml. A command-line argument --app.timeout= would beat all.
⚠ Follow-up traps
Env var name APP_TIMEOUT binds to what key?app.timeout through relaxed binding.
Do lists merge across files? No, a list in a higher source replaces the lower one wholesale.
#externalized-config#precedence
Q74
Your @ConfigurationProperties values are all null. What are the usual causes?
intermediate
The class is not registered (@EnableConfigurationProperties or @ConfigurationPropertiesScan missing, or no @Component).
Wrong prefix or key names (relaxed binding still requires matching words).
No setters on a mutable class (JavaBean binding) or missing constructor binding on an immutable one.
The profile file is not active.
⚠ Follow-up traps
Why use spring-boot-configuration-processor? It generates metadata for IDE completion and warnings.
Does a record need @ConstructorBinding? Not in Boot 3 when there is a single constructor.
#configuration-properties#debugging
Q75
A @Component is not found even though the class exists. What do you check?
basic
Check the package: scanning starts from the @SpringBootApplication class's package. A class in a sibling package (com.other) is missed; fix by moving it or using scanBasePackages/@ComponentScan. Also verify the stereotype annotation and that no profile or conditional excludes it.
⚠ Follow-up traps
Does adding @ComponentScan to the main class keep the default scan? No, it replaces the default base package.
Will @Import work for a non-scanned class? Yes.
#component-scan#startup
Q76
A POST request returns 415 Unsupported Media Type. What are the likely causes?
basic
The request Content-Type is missing or not supported by any HttpMessageConverter for the parameter type, or the mapping declares consumes that does not match. For JSON, send Content-Type: application/json and ensure Jackson is on the classpath.
⚠ Follow-up traps
What if the response type is unacceptable? 406 Not Acceptable, derived from Accept.
Is 400 different? Yes, 400 means the body is malformed or fails binding.
#spring-mvc#content-type
Q77
A @RequestBody has an unknown JSON field. What does Spring Boot do?
intermediate
Boot's auto-configured ObjectMapper disables FAIL_ON_UNKNOWN_PROPERTIES, so unknown fields are silently ignored. A raw new ObjectMapper() would fail with UnrecognizedPropertyException (400). Missing fields become null/default.
Enable strictness with spring.jackson.deserialization.fail-on-unknown-properties=true.
⚠ Follow-up traps
Is a type mismatch (string for int) ignored? No, it gives a 400 (HttpMessageNotReadableException).
Does Boot's mapper write dates as timestamps? No, WRITE_DATES_AS_TIMESTAMPS is disabled (ISO strings).
#jackson#deserialization
Q78
@Valid on a request DTO has no effect. What did you miss?
basic
Common reasons: spring-boot-starter-validation is absent (no validator on the classpath), @Valid is missing on the parameter, constraints are on a getter of a record/class improperly, or nested objects lack @Valid.
⚠ Follow-up traps
Why is @Size not enforced on null? Most constraints treat null as valid; add @NotNull.
Does validation run on @RequestParam simple types? Only with @Validated on the class (or Spring 6.1 built-in method validation).
#validation#debugging
Q79
How do you return a 400 with a field-error list from validation failures?
intermediate
Handle MethodArgumentNotValidException in a @RestControllerAdvice and map getBindingResult().getFieldErrors().
@ExceptionHandler(MethodArgumentNotValidException.class)ResponseEntity<Map<String,String>> invalid(MethodArgumentNotValidException e) { Map<String,String> m = new LinkedHashMap<>(); e.getBindingResult().getFieldErrors() .forEach(f -> m.put(f.getField(), f.getDefaultMessage())); return ResponseEntity.badRequest().body(m);}
⚠ Follow-up traps
Duplicate errors for one field?put keeps the last; collect into a list to keep all.
Where do class-level errors appear? In getGlobalErrors().
#validation#exception-handling
Q80
@WebMvcTest fails with "No qualifying bean of type OrderService". Why?
intermediate
@WebMvcTest loads only the web slice, not @Service/@Repository beans, so the controller's dependency is missing. Provide a mock with @MockitoBean (or @MockBean before Boot 3.4).
Are security filters active? Yes, so unauthenticated calls give 401/403 unless configured.
Why is the whole suite slow after adding many @MockBeans? Each distinct combination builds a new cached context.
#testing#webmvctest#mockbean
Q81
A @DataJpaTest passes on H2 but the same query fails in production PostgreSQL. Why?
advanced
H2 differs in dialect, JSON/array types, case sensitivity, locking, sequence behavior and function support, and @DataJpaTest replaces your datasource by default. Use Testcontainers with the production engine and @AutoConfigureTestDatabase(replace = NONE) (or @ServiceConnection).
⚠ Follow-up traps
Does H2 PostgreSQL mode fix everything? No, it only emulates part of the syntax.
Does Hibernate ddl-auto=create in tests hide migration errors? Yes; run Flyway/Liquibase in tests to validate scripts.
#testing#testcontainers#h2
Q82
Test methods annotated @Transactional all pass, but production fails on commit. What is going on?
advanced
Test transactions roll back by default, so Hibernate may never flush: constraint violations, lazy-loading issues and version conflicts do not appear. Call em.flush()/flush(); clear() in the test to force SQL and a fresh load, or use @Commit / a non-transactional integration test.
⚠ Follow-up traps
Does @Transactional on a test with RANDOM_PORT roll back server-side work? No, the server runs in another thread and transaction.
Why clear() after flush()? To avoid reading from the first-level cache.
#testing#transactional#flush
Q83
/actuator/health shows DOWN because the mail server is unreachable. How do you stop it from restarting the pod?
intermediate
Separate concerns: point the Kubernetes liveness probe to /actuator/health/liveness (internal state only), and the readiness probe to a group containing only critical indicators. Disable or exclude the mail indicator (management.health.mail.enabled=false) or move it out of the readiness group.
Should liveness check the database? Generally no, a DB outage would restart all pods and worsen it.
Overall health with an OUT_OF_SERVICE indicator? Mapped to HTTP 503 as well.
#actuator#health#probes
Q84
You expose all actuator endpoints publicly with include: "*". What is the risk?
intermediate
env, configprops, heapdump, threaddump, loggers (changing log levels), beans and mappings reveal configuration, secrets (masked only partially) and internals; heapdump leaks memory contents. Expose only health/info/prometheus, put management behind authentication or on a separate internal port, and sanitize values (show-values).
⚠ Follow-up traps
Are values in env masked? Keys like password/secret are sanitized by default (since Boot 3 hidden unless show-values is configured), but custom key names may leak.
Does shutdown exist by default? It is disabled by default.
#actuator#security
Q85
A JdbcTemplate query uses string concatenation for a user-supplied name. What is wrong?
basic
It is open to SQL injection: input such as x' OR '1'='1 changes the query. Use ? placeholders or named parameters so the driver sends values separately.
jdbc.query("select * from users where name = ?", mapper, name);
⚠ Follow-up traps
Can placeholders bind a column or table name? No; validate against a whitelist for identifiers and sort columns.
Does using JdbcTemplate alone protect you? No, only parameterization does.
#jdbctemplate#sql-injection
Q86
queryForObject throws EmptyResultDataAccessException. How do you handle it?
basic
queryForObject expects exactly one row: zero rows give EmptyResultDataAccessException, more than one gives IncorrectResultSizeDataAccessException. Use query(...) and take the first element, .stream().findFirst(), or JdbcClient...optional().
⚠ Follow-up traps
Does queryForObject return null for no rows? No, it throws.
Is queryForList for a single column typed? Use queryForList(sql, Long.class, args).
#jdbctemplate#exceptions
Q87
How do you do a batch insert of 5,000 rows efficiently with JdbcTemplate?
With PostgreSQL add reWriteBatchedInserts=true; with MySQL rewriteBatchedStatements=true in the JDBC URL.
⚠ Follow-up traps
Does JdbcTemplate batch run in a transaction automatically? Not unless you add @Transactional; otherwise each batch may auto-commit.
Does it return generated keys? Not easily; use SimpleJdbcInsert/KeyHolder per batch or RETURNING.
#jdbctemplate#batch
Q88
An aspect with @Around on a service never fires for a call inside the same bean. How do you fix it?
intermediate
Self-calls bypass the proxy. Extract the advised method into a collaborator bean, or call it via an injected proxy of itself. If the aspect must cover internal calls, use AspectJ compile- or load-time weaving.
⚠ Follow-up traps
Does the pointcut execution(* com.app.service.*.*(..)) match a method of a class in a sub-package? No, you need .. (service..*).
Aspect not applied at all in Boot? Check the starter spring-boot-starter-aop and that the aspect is a bean (@Component).
#aop#self-invocation#around
Q89
Write an @Around aspect that logs the duration of methods annotated with @Timed.
intermediate
@Aspect@Componentclass TimingAspect { @Around("@annotation(com.app.Timed)") Object time(ProceedingJoinPoint pjp) throws Throwable { long t = System.nanoTime(); try { return pjp.proceed(); } finally { long ms = (System.nanoTime() - t) / 1_000_000; System.out.println(pjp.getSignature() + " took " + ms + " ms"); } }}
Forgetting pjp.proceed() means the target is never called; swallowing exceptions changes behavior.
⚠ Follow-up traps
Why finally? So timing is logged for failures too.
Must you return the proceed result? Yes, otherwise callers get null.
#aop#around#custom-annotation
Q90
Aspect ordering: a logging aspect and a @Transactional proxy both apply. Which runs first?
advanced
Order is controlled by @Order/Ordered (lower value = outermost). The transaction advisor has lowest precedence by default (Ordered.LOWEST_PRECEDENCE), so your aspect wraps the transaction unless you set a different order. A retry aspect must be ordered outside the transaction aspect so each retry gets a fresh transaction.
⚠ Follow-up traps
What if two aspects have the same order? Undefined relative order.
Why does a retry inside the transaction fail? The transaction is already marked rollback-only.
#aop#ordering#transactions
Q91
What does Spring Data do when a repository method name has a typo?
basic
Context startup fails with PropertyReferenceException: No property 'emial' found for type 'User', because derived queries are parsed when the repository proxy is created. @Query methods are validated too (JPQL syntax checked at startup).
⚠ Follow-up traps
Are native @Query strings validated at startup? No, only at execution.
Does findByEmail return null or Optional for no result? Depends on declared type; null for entity, Optional.empty() for Optional.
#spring-data#derived-queries
Q92
A repository method findByEmail returns more than one row. What happens?
intermediate
For a single-entity return type Spring Data throws IncorrectResultSizeDataAccessException. Fix the data model (unique constraint on email), return a List, or use findFirstBy.../findTopBy....
⚠ Follow-up traps
Is a unique index enough alone? Add @Column(unique = true)/constraint in schema so duplicates cannot exist.
Case-insensitive uniqueness? Need a functional index on lower(email) in the DB.
#spring-data#results
Q93
How do you return only two columns from an entity without loading the whole thing?
intermediate
Use an interface or record projection; Spring Data generates a narrow SELECT.
Interface projections with nested/SpEL properties may load the whole entity; closed projections select only required columns.
⚠ Follow-up traps
Are projection results managed? No, so no dirty checking or lazy loading.
Dynamic projections? Add a Class<T> parameter.
#projections#dto#spring-data
Q94
A Page<T> endpoint becomes slow on a 50-million-row table. Why, and what can you do?
advanced
Page runs a count(*) on each request and OFFSET n forces the database to skip n rows. Return Slice to skip the count, cache or approximate totals, and switch to keyset pagination (where id > :lastId order by id limit :size) using a stable sort key and an index.
⚠ Follow-up traps
Is pagination without an ORDER BY safe? No, row order is undefined and pages may overlap.
Ties in the sort column? Add a unique tiebreaker such as the id.
#pagination#performance#keyset
Q95
save() on an entity with a pre-assigned String id triggers a SELECT before INSERT. Why?
advanced
isNew() checks if the id (or @Version) is null; a pre-assigned id means "not new", so save calls merge, which SELECTs to see whether the row exists. Implement Persistable<ID> returning isNew() == true for fresh instances (typically tracked with a @Transient flag), or use a generated id.
⚠ Follow-up traps
Would a @Version Long wrapper help? Yes, null version marks it new.
Does persist avoid the select? Yes, via EntityManager.persist directly.
#spring-data#persistable#merge
Q96
Deleting a parent with children throws a foreign-key violation. Fix?
intermediate
The DB rejects deleting a parent whose rows are referenced. Options: cascade = REMOVE (or orphanRemoval) so Hibernate deletes children first, ON DELETE CASCADE on the FK, or delete children explicitly. CascadeType.REMOVE loads and deletes children one by one; DB-level cascade is faster for large sets.
⚠ Follow-up traps
Does @OnDelete(action = CASCADE) change Hibernate behavior? It emits DDL for DB cascade and skips child deletes.
Is soft-delete an option? Yes, @SQLDelete/@SQLRestriction (Hibernate 6.3+; earlier @Where).
#cascade#foreign-key#delete
Q97
A bidirectional @OneToMany adds a child via parent.getChildren().add(c) but the FK is null. Why?
intermediate
The FK is written from the owning side (@ManyToOne on the child). Adding to the inverse collection alone does not set child.parent, so the column stays null. Keep both sides in sync with a helper.
void addChild(Child c) { children.add(c); c.setParent(this); }
⚠ Follow-up traps
Which side has mappedBy? The collection (inverse) side.
Why is removing during iteration risky?ConcurrentModificationException; use removeIf or the helper carefully.
#mappings#owning-side#bidirectional
Q98
Setting spring.jpa.hibernate.ddl-auto=update in production: what is the problem?
intermediate
update auto-alters schema on startup but never drops columns, cannot rename or migrate data, is unreviewed and unreversible, and may lock tables. Use Flyway or Liquibase for versioned migrations and ddl-auto=validate (or none) in production.
Defaults in Boot: create-drop for embedded DBs, none for others.
⚠ Follow-up traps
Is create safe for tests? Fine for throwaway DBs, never for shared data.
Does validate alter anything? No, it only checks that mappings match the schema.
#ddl-auto#migrations#flyway
Q99
Transactional method calls a remote HTTP API in the middle. What goes wrong at scale?
advanced
The DB connection stays checked out while waiting on the network, so slow responses exhaust the Hikari pool (default 10) and requests queue with Connection is not available timeouts. Keep transactions short: call external services outside the transaction or after commit (@TransactionalEventListener(phase = AFTER_COMMIT)).
⚠ Follow-up traps
Does @Transactional acquire the connection at method entry? Usually lazily with Hibernate on first DB access depending on settings, but never rely on it.
What if the HTTP call succeeds and the commit fails? Inconsistent state; use an outbox pattern.
#transactional#connection-pool#design
Q100
@TransactionalEventListener(AFTER_COMMIT) saves to the database but the data is not persisted. Why?
advanced
The listener runs after the original transaction has committed but its transaction resources are still bound, so a plain @Transactional (REQUIRED) joins the finished transaction and nothing is committed. Annotate the listener with @Transactional(propagation = REQUIRES_NEW).
⚠ Follow-up traps
If no transaction is active when the event is published? The listener is not invoked unless fallbackExecution = true.
Is @Async combined fine? Yes, then the listener runs on another thread and needs its own transaction.
#transactional-event-listener#propagation
Q101
A @Scheduled or @Async method annotated with @Transactional: how do the proxies interact?
advanced
@Async runs the method on another thread; the transaction is thread-bound, so the caller's transaction does not extend into it. The async method starts its own transaction if it carries @Transactional. Exceptions are lost for void returns unless an AsyncUncaughtExceptionHandler is set, and self-invocation again bypasses both.
⚠ Follow-up traps
Does the async method see uncommitted caller data? No, a different transaction cannot read it.
Must @EnableAsync be present? Yes.
#async#transactions#threads
Q102
Which scope does a @RequestScope bean have when injected into a singleton controller?
intermediate
@RequestScope sets proxyMode = TARGET_CLASS by default, so the singleton receives a proxy that delegates to the current request's instance. Outside a request thread (an async or scheduled job) it throws IllegalStateException: No thread-bound request found.
⚠ Follow-up traps
Is a plain @Scope("request") the same? No, it needs proxyMode set explicitly.
Does it propagate to @Async threads? No, request attributes are thread-bound.
#request-scope#scoped-proxy
Q103
SpringApplication fails with "Failed to determine a suitable driver class". Why?
basic
Boot detected spring-boot-starter-data-jpa or JDBC but no spring.datasource.url (and no embedded DB on the classpath). Provide the URL, username, password and the JDBC driver dependency, or exclude DataSourceAutoConfiguration if no DB is needed.
⚠ Follow-up traps
Is driver-class-name required? Usually not; it is inferred from the URL.
What if the driver jar is missing? A similar error about the class not found.
#datasource#startup#debugging
Q104
Port 8080 is already in use at startup. What are your options?
basic
Set server.port in properties, CLI (--server.port=8081) or env (SERVER_PORT); use server.port=0 for a random port in tests (@LocalServerPort reads it). Otherwise stop the process holding the port.
⚠ Follow-up traps
Can the actuator listen on a different port? Yes, management.server.port.
How does a test find the random port? Inject @LocalServerPort with webEnvironment = RANDOM_PORT.