Lessons available in both languages
Java Backend · Interview Prep

Spring Boot & Auto-configuration interview questions & answers

206+ real Spring Boot & Auto-configuration interview questions with model answers, plus free lessons to learn the concepts. Prepare in English & Hinglish, then practise with an AI mock interview.

18 topics · 206+ questions

How Hirenix teaches

One chapter. 90 minutes.
Interview-ready.

Every concept starts with a real-world problem — the kind that actually shows up in production code. Nothing to cram; it just clicks. Every question comes with a model answer: exactly what to say in the room, and why. Then an AI mock interview on the same chapter.

  • 📖Concept in 5 minutesNo jargon — straight to the point
  • 🛠️Real-world problemThe kind production code throws at you
  • 💬Model answerExactly what to say in the room
  • 🧠FlashcardsRevise in 10 minutes
  • 🤖AI mock interviewIt asks follow-ups too
  • 📊Weak topicsSee exactly where you're stuck
Start this chapter — free🌐 English🇮🇳 Hinglish
A student learning an interview concept on Hirenix at home
Video playlistbuilt around a syllabus18h+
Hirenix chapterbuilt around interviews90 min

The difference isn’t the content — it’s the filter. Only what’s actually used in production and actually asked in interviews. Textbook topics the industry never touches don’t make the cut.

Lessons available in both languages

What you’ll learn

  • Why Spring Boot: what it adds on top of Spring
  • How auto-configuration actually works
  • SpringBootApplication and the base-package trapFree account
  • Starters, the BOM, and dependency managementFree account
  • Conditional annotations: OnClass, OnMissingBean, OnPropertyFree account
  • Back-off and overriding: your bean wins, silentlyFree account
  • Externalized configuration and which source winsFree account
  • ConfigurationProperties vs Value, and relaxed bindingFree account
  • Profiles in Boot: profile-specific files and activationFree account
  • The embedded server: port, context path, graceful shutdownFree account
  • REST controllers and JSON mapping with JacksonFree account
  • Error handling: ControllerAdvice and ProblemDetailFree account
  • Actuator: health, info, and production readinessFree account
  • Debugging auto-configuration: the condition evaluation reportFree account
  • RecapFree account
  • Project: URL Shortener REST API
  • Project: Your Own Auto-configuration ModuleFree account
  • Project: Production-Hardened ServiceFree account

Why Spring Boot: what it adds on top of Spring

Spring Boot is not a new framework. It is Spring, plus a set of defaults that save you from writing configuration you were going to write the same way anyway.

That sentence sounds like marketing until you run the program in this lesson. Look at the first line of its output: the context class is AnnotationConfigApplicationContext. That is the exact class from the previous chapter on Spring Core. Boot did not replace the container, the beans, dependency injection, or anything else you learned. It started the same container for you.

What Boot actually adds

Four things, and it is worth being able to name them in an interview:

  1. Auto-configuration. Boot looks at what is on your classpath and registers the beans that combination normally needs. Tomcat on the classpath means a web server gets configured; Jackson on the classpath means JSON conversion gets configured.
  2. Starters. One dependency line that pulls a whole coherent set of libraries at versions known to work together, instead of you picking versions by hand.
  3. An embedded server. Your application starts its own Tomcat inside the JVM. There is no WAR file to build and no external server to install.
  4. Production-ready features. Health checks, metrics and other operational endpoints through Actuator.

The measurement that makes it concrete

The program in this lesson defines zero beans of its own. It has one annotation and a main method. Run it and the container reports 175 bean definitions.

Every one of those came from auto-configuration reading the classpath. That number is not a constant to memorise, and this is the important part: it depends entirely on which jars are present. Add a library, the number goes up, and behaviour changes with it - without you editing a single line of code. That is the whole mechanism of this chapter, visible as one integer.

The three answers that were never Spring's

In the Spring Core chapter you learned that @Value("${some.key}") only resolves if a PropertySourcesPlaceholderConfigurer is registered, that @Repository only translates vendor exceptions if a post-processor is registered, and that AOP annotations only take effect if proxying is switched on. On a plain container, none of those happen by themselves.

The third line of the output settles it: placeholder bean : 1. Boot registered that post-processor. So when a candidate says "Spring resolves ${...} for you", the honest version is that Spring Boot does. Most developers never learn the difference because they have never run a plain container.

When to use it: reach for Spring Boot for essentially any new Spring application - a REST API, a scheduled job, a message consumer, a command-line tool. Convention over configuration is not a slogan here; it means the defaults are the choices an experienced team would have made, so you only write configuration where your needs genuinely differ from the common case.

When NOT to use it: Boot is a poor fit when you must slot into an existing deployment that owns the server - an organisation that deploys WAR files onto a managed application server, for example. It is also the wrong tool when you need a very small library rather than an application, since Boot's value is in wiring an application together. And there is a real cost even when it fits: a Boot application does a great deal that you did not write, so when something behaves unexpectedly you must be able to read what auto-configuration decided. That skill is the rest of this chapter.

The reason to learn the mechanism rather than the boilerplate it removes is simple: interviews rarely ask you to praise Boot. They ask why a bean is missing, why a property is not being read, or why the application starts differently on a colleague's machine. Every one of those questions is about auto-configuration.

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@SpringBootApplication
public class WhyBoot {
  public static void main(String[] args) {
    System.setProperty("spring.main.web-application-type", "none");
    try (ConfigurableApplicationContext ctx = SpringApplication.run(WhyBoot.class, args)) {
      System.out.println("context class    : " + ctx.getClass().getSimpleName());
      System.out.println("beans registered : " + ctx.getBeanDefinitionCount());

      String[] placeholder = ctx.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class);
      System.out.println("placeholder bean : " + placeholder.length
          + (placeholder.length > 0 ? " (" + placeholder[0] + ")" : ""));
    }
  }
}

How auto-configuration actually works

Auto-configuration is the one idea this whole chapter rests on. Almost every Spring Boot interview question that sounds like something else - "why is this bean missing", "why did adding a library change the behaviour", "why does it work on my machine" - is really a question about it.

The mechanism has three steps, and none of them are magic.

Step 1: a list of candidates

Every jar that wants to contribute auto-configuration ships a plain text file at META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. One fully-qualified class name per line.

The program below reads that file off its own classpath rather than trusting anyone's description of it. On this classpath there are 2 such files - one from spring-boot-autoconfigure, one from spring-boot-actuator-autoconfigure - listing 279 candidate classes between them.

That file is worth remembering by name. Older tutorials will tell you the list lives in spring.factories. That was true up to Boot 2.7; from Boot 3 the AutoConfiguration.imports file is the mechanism, and quoting the old one in an interview dates you immediately.

Step 2: conditions decide which ones survive

279 candidates are considered. Nowhere near 279 are applied. Each candidate is guarded by conditions - is this class on the classpath, has the user already defined this bean, is this property set - and a candidate whose conditions fail contributes nothing. Those conditions are their own topic; what matters here is that the list is a set of candidates, not a set of decisions.

Step 3: the survivors are ordered

Some auto-configurations only make sense after others have run. The output shows WebMvcAutoConfiguration declaring that it runs after DispatcherServletAutoConfiguration, TaskExecutionAutoConfiguration and ValidationAutoConfiguration.

Note how that was measured. The class has no @AutoConfigureAfter annotation on it at all - the program prints false for exactly that check. In Boot 3 the ordering is declared through the @AutoConfiguration annotation's own after and afterName attributes. @AutoConfigureAfter still exists and still works, but the framework's own classes have moved on, so an answer built only around it describes an older Boot than the one you will be hired to work on.

What it is actually worth

The first two lines of the output are the honest measure of the feature. A plain @Configuration in a bare Spring container produces 6 bean definitions - Spring's own infrastructure and nothing else. Change nothing but the annotation, and @SpringBootApplication produces 176.

Do not memorise 176. Earlier lessons in this chapter measured 156, 175 and 177 from the same machine, because the classpath and the scanned package were different each time. A bean count that moves when you add a jar is not a flaw in the demo - it is the feature, stated numerically.

When to use it: rely on auto-configuration for the ordinary parts of an application - the web server, JSON conversion, a datasource from properties. It is at its best where your requirements match what most applications need, which is most of the time.

Trade-off: you gain a working application in exchange for a system that made decisions you never saw. When behaviour surprises you, the cost comes due, and the only way to pay it is to read what auto-configuration actually decided rather than guess. The report that shows you is covered later in this chapter. The habit worth forming now is the one this lesson demonstrates: when you want to know what Boot did, ask the running application - print the count, read the imports file, reflect on the annotation - instead of trusting a blog post about it.

@EnableAutoConfiguration is the switch that starts all of this. @SpringBootApplication includes it, which is why you rarely write it yourself.

package auto2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;

public class HowAuto {

  @Configuration
  static class PlainConfig { }

  @SpringBootApplication
  static class BootApp { }

  static final String IMPORTS =
      "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";

  public static void main(String[] args) throws Exception {
    try (var plain = new AnnotationConfigApplicationContext(PlainConfig.class)) {
      System.out.println("plain @Configuration beans   : " + plain.getBeanDefinitionCount());
    }

    System.setProperty("spring.main.web-application-type", "none");
    try (ConfigurableApplicationContext boot = SpringApplication.run(BootApp.class, args)) {
      System.out.println("@SpringBootApplication beans : " + boot.getBeanDefinitionCount());
    }

    int files = 0, candidates = 0;
    Enumeration<URL> urls = HowAuto.class.getClassLoader().getResources(IMPORTS);
    while (urls.hasMoreElements()) {
      files++;
      try (BufferedReader r = new BufferedReader(
          new InputStreamReader(urls.nextElement().openStream()))) {
        String line;
        while ((line = r.readLine()) != null) {
          line = line.trim();
          if (!line.isEmpty() && !line.startsWith("#")) candidates++;
        }
      }
    }
    System.out.println("imports files on classpath   : " + files);
    System.out.println("candidates listed in them    : " + candidates);

    Class<?> webmvc = Class.forName(
        "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration");
    System.out.println("@AutoConfigureAfter present  : "
        + (webmvc.getAnnotation(org.springframework.boot.autoconfigure.AutoConfigureAfter.class) != null));
    AutoConfiguration meta = webmvc.getAnnotation(AutoConfiguration.class);
    System.out.print("WebMvc runs after            :");
    for (String n : meta.afterName()) System.out.print(" " + n.substring(n.lastIndexOf('.') + 1));
    for (Class<?> c : meta.after()) System.out.print(" " + c.getSimpleName());
    System.out.println();
  }
}

Project: URL Shortener REST API

This is the chapter's entry project. It is small on purpose - one file, no database - because the point is not the URL shortener. The point is that every Boot idea you have met so far shows up in a service this simple, and an interviewer can ask about any of them from this one screen of code.

What it does

POST /links takes a target URL and returns a short code. GET /{code} redirects to the original. An unknown code produces a proper error, and an invalid request body is rejected before your code runs.

What it exercises, and where each piece came from

Typed configuration. shortener.base-url and shortener.code-length bind onto a @ConfigurationProperties class carrying @Validated. Nothing is read with a string key at runtime. If someone deploys with a blank base URL the application refuses to start, rather than serving broken short links.

Constructor injection. Links takes Props, and Api takes Links - the same dependency injection from the Spring Core chapter, unchanged. Boot did not replace it; it just created the container for you.

A layered shape. The controller handles HTTP, the @Service holds the logic, the properties class holds configuration. That separation is what makes the service testable, and it is what interviewers look for when they ask you to "design an endpoint".

Correct HTTP. POST /links returns 201 with a Location header, not 200 with a body only. GET /{code} returns 302 with the target in Location, which is what a redirect actually is at the protocol level. These are exactly the status codes ResponseEntity exists to let you choose.

Real error handling. An unknown code throws a domain exception, and a @RestControllerAdvice turns it into a ProblemDetail:

404 {"type":"about:blank","title":"Unknown short code",
     "status":404,"detail":"code not found: zzzzzz","instance":"/zzzzzz"}

Note type is about:blank here - the handler set a title and detail but no type URI, and that is the RFC 7807 default. Setting a real type URI is a one-line improvement worth making in a production service.

Validation at the edge. @Valid @RequestBody with @NotBlank rejects an empty URL with 400 before a single line of business logic executes.

Try these

  1. Make the error response better: give the ProblemDetail a real type URI, and add a handler for MethodArgumentNotValidException so the 400 says which field failed instead of just "Bad Request".
  2. Replace the hash-based code with a random one, and handle the collision that becomes possible - which is a genuine design question, not a formality.
  3. Add @ConditionalOnProperty so a shortener.stats.enabled flag switches an optional hit-counter endpoint on and off, and confirm with the condition report that it is really absent when the flag is off.
  4. Expose actuator with only health and metrics, then check that /actuator/env is still 404.

The honest caveat: the store is a ConcurrentHashMap, so everything disappears on restart and nothing is shared between instances. That is deliberate - persistence is the next chapter's subject, and adding it here would bury the Boot concepts under JPA setup.

package shortener;

@SpringBootApplication
@EnableConfigurationProperties(Shortener.Props.class)
public class Shortener {

  @Validated
  @ConfigurationProperties(prefix = "shortener")
  public static class Props {
    @NotBlank private String baseUrl;
    private int codeLength = 6;
    public void setBaseUrl(String v){ this.baseUrl=v; } public String getBaseUrl(){ return baseUrl; }
    public void setCodeLength(int v){ this.codeLength=v; } public int getCodeLength(){ return codeLength; }
  }

  record CreateRequest(@NotBlank String url) { }
  record CreateResponse(String code, String shortUrl, String target) { }
  static class UnknownCode extends RuntimeException { UnknownCode(String c){ super("code not found: " + c); } }

  @Service
  static class Links {
    private final Map<String, String> store = new ConcurrentHashMap<>();
    private final Props props;
    Links(Props props) { this.props = props; }          // constructor injection

    CreateResponse create(String target, int port) {
      String code = Integer.toHexString(target.hashCode()).replace("-", "");
      code = (code + "000000").substring(0, props.getCodeLength());
      store.put(code, target);
      return new CreateResponse(code, props.getBaseUrl() + ":" + port + "/" + code, target);
    }
    String resolve(String code) {
      String t = store.get(code);
      if (t == null) throw new UnknownCode(code);
      return t;
    }
  }

  @RestController
  static class Api {
    private final Links links;
    private final Environment env;
    Api(Links links, Environment env) { this.links = links; this.env = env; }

    @PostMapping("/links")
    ResponseEntity<CreateResponse> create(@Valid @RequestBody CreateRequest req) {
      int port = Integer.parseInt(env.getProperty("local.server.port", "0"));
      CreateResponse r = links.create(req.url(), port);
      return ResponseEntity.created(URI.create(r.shortUrl())).body(r);
    }

    @GetMapping("/{code}")
    ResponseEntity<Void> follow(@PathVariable("code") String code) {
      return ResponseEntity.status(HttpStatus.FOUND).location(URI.create(links.resolve(code))).build();
    }
  }

  @RestControllerAdvice
  static class Errors {
    @ExceptionHandler(UnknownCode.class)
    ProblemDetail unknown(UnknownCode e) {
      ProblemDetail pd = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
      pd.setTitle("Unknown short code");
      return pd;
    }
  }
}

# application.properties
#   shortener.base-url=http://localhost
#   shortener.code-length=6

Spring Boot & Auto-configurationinterview questions & answers

10 sample questions below — 206+ in the full bank inside.

What is the difference between @SpringBootApplication and @EnableAutoConfiguration?

@EnableAutoConfiguration turns on auto-configuration and nothing else. @SpringBootApplication is a convenience that bundles three annotations: @SpringBootConfiguration, @EnableAutoConfiguration and @ComponentScan. So the difference is the other two - configuration-class semantics and component scanning rooted at that class's package. If you ever need auto-configuration without scanning, you would use @EnableAutoConfiguration on its own.

In simple terms: You can verify the composition at runtime with SpringBootApplication.class.getAnnotations() rather than reciting it, which is worth mentioning because it is the same habit the rest of the chapter uses.

Explain auto-configuration to a junior developer in four sentences.

Starters put a set of jars on your classpath. Each of those jars lists auto-configuration candidates in a file called AutoConfiguration.imports. Conditions - on a class being present, on a property, on a bean being absent - decide which candidates actually apply. And because @ConditionalOnMissingBean guards most of them, anything you define yourself wins over the default.

In simple terms: Being able to compress a mechanism into four sentences is itself the test. If the explanation needs ten minutes, the candidate is describing symptoms rather than the mechanism, and interviewers notice that immediately.

Summarise Actuator in three sentences.

Actuator answers operational questions about a running application - health, version, metrics - through HTTP endpoints, and it arrives as one dependency. By default only health is published; everything else stays 404 until named in management.endpoints.web.exposure.include, so exposure is opt-in per endpoint. Securing the application does not automatically secure Actuator, and health deliberately stays reachable because probes cannot authenticate.

In simple terms: Three sentences covering what it is, the conservative default, and the security nuance. A summary that omits the last one leaves the listener with a wrong mental model of who can reach what.

What does auto-configuration actually do, and what is the role of @EnableAutoConfiguration?

Auto-configuration inspects what is on the classpath and registers the beans that combination normally needs - Tomcat present means a web server gets configured, Jackson present means JSON conversion gets configured. @EnableAutoConfiguration is the switch that starts that process. You rarely write it yourself because @SpringBootApplication already includes it, along with @SpringBootConfiguration and @ComponentScan.

In simple terms: The common weak answer is "it configures things automatically", which restates the name. Naming the classpath as the input is what shows understanding, because everything else in the chapter - starters, conditions, back-off - hangs off that one idea.

What is Spring Boot Actuator and what does it give you?

It is the part of Boot that answers questions about the running application rather than doing its business work - is it alive, what version is it, how is it behaving. It arrives as one dependency and provides endpoints such as health, info and metrics. Measured with no configuration, /actuator/health answered 200 with {"status":"UP"}, which is the single feature that earns the dependency in any deployed service.

In simple terms: The distinction between business work and operational questions is the framing worth having. It also explains why Actuator is a separate dependency rather than part of the web starter.

Why add Actuator to every deployed service, even a small one?

Because health alone earns it. An orchestrator that cannot tell whether your application is alive will either route traffic into a broken instance or restart a healthy one, and both are worse than the cost of one dependency. Small services are not exempt - they fail the same way, and they are usually the ones nobody is watching closely, so an automated health signal matters more rather than less.

In simple terms: The point about small services is the one worth making. Teams often skip operational tooling on services they consider minor, which is exactly where a silent failure goes unnoticed longest.

Which Actuator endpoints matter in practice, and what is each for?

health is polled by a load balancer or orchestrator to decide whether this instance should receive traffic - in Kubernetes it backs the liveness and readiness probes. info carries build and version details, which is how you answer "which version is actually deployed" without asking anyone. metrics exposes Micrometer counters and timers for dashboards. env lists every property source and value, which is powerful and is exactly why it should not be public.

In simple terms: Listing them is easy; saying who consumes each one is what shows operational experience. The note on env also sets up the exposure question that usually follows.

What does server.servlet.context-path=/api do?

It moves every endpoint under that prefix - the same handler that answered at /ping now answers at /api/ping and no longer at /ping. It is often used when a service sits behind a shared gateway that routes by path prefix. Worth remembering when debugging a sudden wave of 404s after a configuration change, because nothing about the controllers changed.

In simple terms: The debugging note is the value here. A context path added by someone editing deployment configuration produces 404s that look like a routing bug in the application.

Why does java -jar app.jar --server.port=9090 always work?

Because command-line arguments sit at the top of the resolution order, above system properties, environment variables and every file. Whatever is packaged inside the jar cannot outrank them. That is what makes the form so useful for one-off runs and for overriding a value in an emergency, and it is also why a commandLineArgs source only appears in the printed source list when arguments were actually passed.

In simple terms: The detail about the source appearing only when arguments exist is small but shows you have actually looked at the list rather than memorised a diagram.

How do you disable one specific auto-configuration class?

Either @SpringBootApplication(exclude = SomeAutoConfiguration.class) in code, or the property spring.autoconfigure.exclude with the fully-qualified class name, which is the form you use when the decision belongs to a deployment rather than to the source. Both remove the class from consideration entirely, whether or not you provide a replacement.

In simple terms: Knowing both forms matters in practice: the annotation is a compile-time decision baked into the artifact, while the property can differ per environment, which is often what you actually want.

196+ more Spring Boot & Auto-configuration questions inside

Create a free account to read the full question bank, learn every topic, and practise with an AI mock interview.

Unlock all questions — free

Ready to practise Spring Boot & Auto-configuration?

Unlock every topic free, then face an AI interviewer that asks follow-ups and grades your answers.