Last updated 19 September 2026. Default examples are mid-level Spring and Java 17–21. Junior and senior sit in labeled sections so the first screen is not a fresher dump.
Spring interviews in 2026 still start with inversion of control, then jump to Boot, MVC, and data access. This hub is the canonical Spring interview page on Javapedia. Part II remains a sibling catalog; do not treat both as competing head terms. Default examples use constructor injection and Spring Framework 6 / Boot 3 on Java 17+.
Junior
Spring is a container that creates objects, wires dependencies, and manages their lifecycle. A bean is an object the container owns. The ApplicationContext is the usual entry point; BeanFactory is the lighter contract underneath. Interviewers ask why we prefer constructor injection: required dependencies become constructor arguments, the field can be final, and tests can new the class without a Spring test slice.
@Component, @Service, @Repository, and @Controller are stereotype annotations. They all register a bean. @Repository additionally translates persistence exceptions. @Autowired on a single constructor is optional in modern Spring; the container uses that constructor anyway. @Qualifier disambiguates when two beans share a type. @Primary picks a default. If you cannot explain the difference between those three, you are not done with junior Spring.
This is wrong if you still show XML as the primary configuration story. Java config and component scanning are the default. XML still exists in old banks; mention it as legacy, not as how you would start a service tomorrow.
Bean scopes you must name: singleton (default), prototype, request, session. Singleton plus mutable instance state is a thread-safety bug. Prototype is not a request scope; each injection point gets a new instance at injection time, not per HTTP request, unless you look it up again.
Mid-level
Mid-level interviews test whether you can reason about the container, not recite annotations. ApplicationContext refresh loads bean definitions, validates, and instantiates singletons. A circular dependency between two constructor-injected singletons fails at startup. Setter or @Lazy injection can hide the cycle; that is a smell, not a design. Prefer extracting a third type.
@Transactional is a proxy by default. Self-invocation inside the same class does not hit the proxy, so the transaction advice does not run. The proxy starts a transaction, joins or suspends according to propagation, and translates unchecked exceptions into rollback. Checked exceptions do not roll back unless rollbackFor says so. REQUIRED is the default propagation. REQUIRES_NEW suspends the outer transaction; if you do not know what that does to an outer rollback, say so instead of guessing.
Spring MVC: DispatcherServlet is the front controller. HandlerMapping finds a @RequestMapping method. HandlerAdapter invokes it. HandlerInterceptor runs around that invocation and sees the HandlerMethod. A servlet Filter runs earlier, on the raw request, and does not know which controller will run. That distinction is the same one we used on the harvest SERP for filter versus interceptor.
Profiles and Environment separate credentials from code. @Profile("prod") plus spring.profiles.active is the interview answer. Do not hard-code DataSource URLs. @ConfigurationProperties maps a prefix to a typed object; @Value is fine for one knob and messy for a dozen.
Testing: @SpringBootTest loads the context. @WebMvcTest loads MVC slice only. @DataJpaTest loads JPA slice. If the candidate boots the full context for a controller unit test, they will lose time and hide the real failure.
Senior
Senior questions go to configuration classes, BeanPostProcessor order, and how Boot's auto-configuration conditions interact with your beans. @ConditionalOnMissingBean is why your custom DataSource replaces Boot's. @ConditionalOnClass is why a starter is inert when the jar is absent. Debug with --debug or the conditions report, not by guessing annotation order.
AOP proxies: JDK proxies need an interface. CGLIB subclasses the concrete class. final methods are not advised. You should be able to explain why @Transactional on a private method is dead code. Transaction synchronization and afterCommit hooks matter when you publish events that must not fire on rollback.
Spring 6 / Framework 6 dropped javax in favor of jakarta. Boot 3 needs that namespace. An interview that still shows javax.servlet.Filter on a Boot 3 service is testing whether you notice. Virtual threads are available; they do not make every blocking JDBC call free. Pinning inside synchronized still exists. Measure before you flip the JVM flag in production.
Observability: Micrometer meters, Actuator endpoints, and tracing context propagation across ThreadLocal-hostile executors. If you hand a request to an unbounded executor without wrapping the context, you lose the trace. That is a senior answer.
Probe yourself
Why does constructor injection fail on a circular dependency when setter injection might not?
The container must satisfy constructor args before the bean exists. Setters run after a raw instance exists, so the cycle can be deferred. Prefer breaking the cycle over hiding it.
Why can @Transactional on a method in the same class appear to do nothing?
Default advice is on the proxy. this.foo() does not enter the proxy, so no transaction starts.
Filter or HandlerInterceptor for adding a correlation id to every request, including static 404s?
A Filter sees the request before MVC mapping. Interceptors never run if no handler matched.
Related questions on this topic are linked below. Read the full answer on the question URL; this hub does not repeat those answers.
Pitfalls interviewers still use
Field injection in production code still appears in tutorials from 2015. It hides required dependencies, breaks immutability, and makes the class unusable without a container. If you walk in with @Autowired on fields, expect a follow-up on how you would test the class with two collaborators. The answer is a constructor, not ReflectionTestUtils.
Another trap is treating @ComponentScan as optional because Boot scans for you. It scans from the application class package. A utility in a sibling package is invisible. The failure is a missing bean at startup, not a runtime NPE, if you injected it. If you looked it up with getBean, you get a runtime failure and a worse story.
People still say Spring MVC and Spring WebFlux are interchangeable. They share annotations and little else in the execution model. WebFlux is event-loop plus reactive types. MVC is a servlet thread (or a virtual thread) plus blocking APIs. Pick one per service unless you have a concrete bridge, such as a reactive client inside an MVC app.
Transaction boundaries drawn on repositories look tidy and fail when two repository calls must be one unit. The service method is the boundary. If the interviewer draws a diagram with a repository-level transaction around each insert and then asks about a money transfer, they are testing whether you move the annotation up.
Bean naming collisions happen when two @Service classes share a default name after a refactor. The second definition wins or the context fails, depending on allow-bean-definition-overriding. Do not turn that flag on to hide a duplicate. Rename or @Qualifier.
For the room: walk a request from DispatcherServlet to a @Transactional service to a repository flush. If you can do that without notes, you pass mid-level Spring. If you can add a conditions report and a self-invocation failure, you pass senior.
How to answer in the room
Open with the request path, not with a list of annotations. Say: a servlet container hands the request to DispatcherServlet, a HandlerMapping selects a controller method, a HandlerAdapter invokes it, then a @Transactional service runs, then a repository flush. If you cannot put those boxes in order, stop and draw them. Interviewers who hire for banks still use this drawing as a mid-level filter.
When they ask what Spring is, do not say 'it is a framework'. Say it is a container that owns object lifetime and injects collaborators. Then give one reason constructor injection wins: the graph is visible, the fields can be final, and a unit test can construct the class. If they ask about field injection, say it is a tutorial leftover and you would reject it in review.
On transactions, narrate one money-moving method. The annotation belongs on the service, not the repository. REQUIRED joins an existing transaction. REQUIRES_NEW suspends it. Unchecked exceptions roll back; checked ones do not unless rollbackFor says so. Self-invocation skips the proxy. If you have never seen a missing rollback because of this.foo(), say you have seen the code review comment, not that you invented the proxy model last night.
Boot questions should go to auto-configuration, not to 'starters are convenient'. Name a condition: OnMissingBean, OnClass, OnProperty. Say how you would prove why a DataSource was created: the conditions report, not a guess. If the service is Boot 3, say jakarta, not javax. If someone still pastes javax.servlet.Filter, call it out.
Profiles and secrets: Environment plus env vars. No passwords in application.yml in Git. @ConfigurationProperties for a group of knobs. @Value for one. If they ask about Kubernetes, say the same Environment contract; the source changes, the code should not.
Close the Spring interview by naming one thing you would measure in production: a hikari connection wait, a transaction rollback meter, or a missing Micrometer trace after an executor hop. That is mid-to-senior. Reciting @Component versus @Service is junior and they already know you can Google it.
This hub does not replace the child question pages. Use those URLs when a single distinction needs a long example. Use this page when the query is 'Spring interview questions' and the reader needs a map, not a 200-question dump.