RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
Spring Boot questions
MediumSpring Boot#46 min readJul 11, 2026

Explain @SpringBootApplication.

spring-boot
basics
annotations
Practice modeTest yourself instead of reading straight through

Think of @SpringBootApplication as the one switch that says: find my beans, set up the usual Spring pieces, and start the app from here. Interviewers love it because it tests whether you know Spring Boot is mostly a smart shortcut, not magic.

Question: Explain @SpringBootApplication.

Answer: @SpringBootApplication is a convenience annotation used on the main Spring Boot class. It combines three things: @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan. In simple terms, it tells Spring Boot to treat the class as the app entry point, automatically configure common features, and look for components in the same package and below.

Interview-Ready Answer: I’d say @SpringBootApplication is a shortcut annotation for the main class in a Spring Boot app. It bundles configuration, auto-configuration, and component scanning into one place, so Spring Boot can find my beans and set up defaults based on the classpath. A nice detail is that it scans the package of the main class and its subpackages, so package placement matters a lot.

🧠 Memory Map
Memory map — visual summary of this topic

What it really is

@SpringBootApplication is a meta-annotation, which means it is an annotation placed on another annotation to bundle behavior. It does not add one giant new feature; it simply groups three existing Spring features into a single, easy-to-use entry point.

How it works under the hood

  1. Spring Boot starts from the class marked with @SpringBootApplication, usually the one with main() and SpringApplication.run(...).
  2. @SpringBootConfiguration marks that class as a Spring configuration class. It is a specialized form of @Configuration, so Spring knows this class can define beans and application settings.
  3. @ComponentScan scans the package of that class and its subpackages for Spring stereotypes such as @Component, @Service, @Repository, and @Controller. This is how your app finds user-written beans without listing each one manually.
  4. @EnableAutoConfiguration tells Boot to inspect the classpath and register sensible defaults when certain conditions match. For example, if Spring MVC is present, Boot can configure a web stack; if a database driver is present, it may configure a datasource.
  5. Auto-configuration is conditional. Spring Boot uses rules such as @ConditionalOnClass, @ConditionalOnMissingBean, and @ConditionalOnProperty so it only creates beans when they make sense.
  6. Since Spring Boot 3, auto-configuration classes are discovered through META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports; older Boot 2 versions used spring.factories. The idea is the same: Boot reads metadata and applies matching configs.

Why it matters

Without this annotation, you would often write the three pieces separately. That works, but it is noisier and easier to get wrong. The combined annotation is a readability win and a consistency win: almost every Boot app starts the same way, so the convention is simple to remember.

ApproachMeaningBest use
@SpringBootApplicationOne shortcut for the common trioMost apps
Three separate annotationsSame behavior, spelled outRare custom setups

Important edge cases

  • It does not create every bean by itself. It only enables scanning and auto-configuration.
  • Package location matters. If your main class sits too deep, sibling packages are not scanned. A common fix is to place the main class at the root package of the app.
  • Avoid the default package (no package declaration). It makes scanning too broad and is a known Spring Boot anti-pattern.
  • You can opt out of unwanted auto-configurations with exclude or excludeName.

Performance and mental model

Think of startup as two loops: component scanning and auto-config evaluation. Both are roughly linear in the amount of work they inspect, so bigger packages and more starters mean a little more startup time. In a typical app, Spring may inspect hundreds of classes and evaluate dozens to more than a hundred auto-configuration candidates, but only a smaller subset becomes active. The key point: Boot is fast because it reads metadata first and uses conditions to avoid creating unnecessary beans.

Memory hook: It is the front door sign that also turns on the lights and opens the rooms. One annotation, three jobs.

Real-world story

Imagine a checkout service in an e-commerce platform. The team adds a new PaymentController, but a refactor moves the main class into com.acme.checkout.app while the controller lives in com.acme.checkout.web. The app still starts, but every payment route returns 404 because the controller is outside the component-scan path.

The symptom is subtle: startup logs look fine, health checks pass, but request mapping logs never show the new endpoint. In production, users click “Pay Now” and get a blank error page or a generic 404. The fix is to place the main class at the root package, or explicitly set scanBasePackages so Boot scans the packages that contain controllers and services.

Spring Boot
package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    private final GreetingService greetingService;

    @Autowired
    public DemoApplication(GreetingService greetingService) {
        // Constructor injection is preferred because it makes dependencies explicit
        // and keeps the app easy to test.
        this.greetingService = greetingService;
    }

    public static void main(String[] args) {
        // Spring Boot starts here, finds this class, scans this package and subpackages,
        // and applies auto-configuration based on what is on the classpath.
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        // This confirms that the service bean was discovered by component scanning.
        System.out.println(greetingService.greet("Spring Boot"));

        // Edge case / failure path: the service rejects divide-by-zero instead of failing silently.
        try {
            System.out.println("10 / 0 = " + greetingService.divide(10, 0));
        } catch (IllegalArgumentException ex) {
            System.out.println("Handled startup edge case: " + ex.getMessage());
        }
    }
}

@RestController
@RequestMapping("/api")
class GreetingController {

    private final GreetingService greetingService;

    GreetingController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/hello/{name}")
    public String hello(@PathVariable String name) {
        return greetingService.greet(name);
    }

    @GetMapping("/divide")
    public String divide(@RequestParam int numerator, @RequestParam int denominator) {
        try {
            return "Result = " + greetingService.divide(numerator, denominator);
        } catch (IllegalArgumentException ex) {
            // The controller translates a domain error into a proper HTTP 400 response.
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage(), ex);
        }
    }
}

@Service
class GreetingService {

    String greet(String name) {
        return "Hello, " + name + "!";
    }

    int divide(int numerator, int denominator) {
        if (denominator == 0) {
            throw new IllegalArgumentException("Denominator must not be zero");
        }
        return numerator / denominator;
    }
}

Follow-up & Tricky Questions:

Follow-up questions

  • What do the three composed annotations do individually? @SpringBootConfiguration marks the app class as configuration, @EnableAutoConfiguration turns on Boot’s condition-based defaults, and @ComponentScan finds your beans in the package tree.
  • How does Boot decide which auto-configurations to apply? It checks the classpath, environment, and existing beans, then activates only the configurations whose conditions match.
  • How do you exclude an unwanted auto-configuration? Use @SpringBootApplication(exclude = ...) or excludeName when a starter adds something you do not want, such as an auto-configured datasource.
  • What happens if your beans are in another package? They will not be found by default. Move the main class to a higher root package or set scanBasePackages / scanBasePackageClasses.
  • Why is this annotation usually on the main class? Because the main class becomes the natural anchor for scanning and auto-configuration, which keeps the app layout predictable.

Tricky / gotcha questions

  • Does @SpringBootApplication itself create beans? No. It enables scanning and auto-configuration; the actual beans come from your components and Boot’s configuration classes.
  • Is it mandatory in every Boot app? No. You can write the three underlying annotations separately, but the combined form is the standard and clearest choice.
  • Does it scan the whole classpath? No. It scans the package of the annotated class and its subpackages, not every class in every dependency.

Common Mistakes:

  • Mistake: thinking the annotation is only for startup. Correction: it also drives bean discovery and auto-configuration for the whole app.
  • Mistake: putting the main class in a deep subpackage. Correction: place it at the root package so controllers, services, and repositories are all scanned.
  • Mistake: assuming it creates every dependency automatically. Correction: Boot only auto-configures what matches the classpath and conditions.
  • Mistake: mixing up component scan and auto-configuration. Correction: component scan finds your code; auto-configuration wires common framework beans.

Memory Hook: One annotation, three jobs: configuration, scanning, and smart defaults.

Cheat Sheet:

  • @SpringBootApplication is a convenience annotation on the main class.
  • It combines @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan.
  • It scans the main package and subpackages for components.
  • It enables conditional auto-configuration from the classpath.
  • It does not scan the entire classpath or create every bean by itself.

Practice Tasks:

  • Move a controller into a sibling package and observe the 404, then fix it by moving the main class or changing scan settings.
  • Remove a starter dependency, start the app, and notice which auto-configured beans disappear.
  • Replace @SpringBootApplication with the three separate annotations and confirm the app still works the same.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; @SpringBootApplication public class DemoApplication implements CommandLineRunner { private final GreetingService greetingService; @Autowired public DemoApplication(GreetingService greetingService) { // Constructor injection is preferred because it makes dependencies explicit // and keeps the app easy to test. this.greetingService = greetingService; } public static void main(String[] args) { // Spring Boot starts here, finds this class, scans this package and subpackages, // and applies auto-configuration based on what is on the classpath. SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) { // This confirms that the service bean was discovered by component scanning. System.out.println(greetingService.greet("Spring Boot")); // Edge case / failure path: the service rejects divide-by-zero instead of failing silently. try { System.out.println("10 / 0 = " + greetingService.divide(10, 0)); } catch (IllegalArgumentException ex) { System.out.println("Handled startup edge case: " + ex.getMessage()); } } } @RestController @RequestMapping("/api") class GreetingController { private final GreetingService greetingService; GreetingController(GreetingService greetingService) { this.greetingService = greetingService; } @GetMapping("/hello/{name}") public String hello(@PathVariable String name) { return greetingService.greet(name); } @GetMapping("/divide") public String divide(@RequestParam int numerator, @RequestParam int denominator) { try { return "Result = " + greetingService.divide(numerator, denominator); } catch (IllegalArgumentException ex) { // The controller translates a domain error into a proper HTTP 400 response. throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getMessage(), ex); } } } @Service class GreetingService { String greet(String name) { return "Hello, " + name + "!"; } int divide(int numerator, int denominator) { if (denominator == 0) { throw new IllegalArgumentException("Denominator must not be zero"); } return numerator / denominator; } }