How Spring Boot Works
IntermediateSpring Boot is an opinionated wrapper around the Spring Framework that eliminates XML configuration and gets you to a running production-ready service in minutes. At its core, Spring Boot works by scanning your classpath at startup, detecting what libraries you have (Hibernate on the classpath? Configure a DataSource automatically), and wiring up everything your application needs without you writing a single line of boilerplate config. The magic is auto-configuration: hundreds of @Configuration classes that activate conditionally based on what you have in your project.
Think of Spring Boot as a smart hotel concierge
When you check in to a hotel, you don't explain how to make a bed or set up the TV. The hotel detects that you're a guest and automatically prepares your room with everything a guest typically needs — bed made, towels set out, TV connected. If you bring your own pillow, it backs off on that. Spring Boot does the same: it detects what's on your classpath and automatically configures what you need. If you define your own DataSource bean, it backs off on creating one. Convention over configuration — but you always override any convention.
Step by Step
Key Concepts
IoC Container (ApplicationContext)
The core of Spring. A registry of beans and their dependencies. When your app starts, Spring reads all @Configuration classes and @Component-annotated classes, instantiates them in the right order (respecting dependencies), injects required beans, and stores everything in the ApplicationContext. Beans are singleton-scoped by default — one instance shared across the application.
Bean
Any object managed by the Spring container. Created by Spring, configured by Spring, injected by Spring. You declare beans with @Component (auto-detection) or @Bean methods inside @Configuration classes (explicit). Scope: singleton (one per context — default), prototype (new instance per injection), request (one per HTTP request), session (one per HTTP session).
Auto-Configuration
Hundreds of @Configuration classes in spring-boot-autoconfigure that activate conditionally using @ConditionalOn* annotations. They wire up DataSource, JPA EntityManagerFactory, Jackson ObjectMapper, Spring Security filter chain, caching, metrics, and dozens more — if and only if the relevant library is on the classpath and you haven't already defined the bean yourself.
Dependency Injection
The pattern where objects declare what they need (dependencies) and the container provides them. Three injection types: constructor injection (preferred — dependencies required at construction, supports immutability), setter injection (optional dependencies), field injection (@Autowired on a field — convenient but harder to test). Spring resolves beans by type first; if multiple candidates exist, use @Qualifier or @Primary to disambiguate.
Spring MVC DispatcherServlet
The front controller that handles all incoming HTTP requests. Routes requests to @Controller or @RestController methods based on @RequestMapping. Applies @ExceptionHandler methods for error handling. Uses HttpMessageConverters (e.g., Jackson for JSON) to serialise/deserialise request/response bodies. @RestController = @Controller + @ResponseBody — every method returns the response body directly (no view rendering).
Spring Data JPA
Eliminates DAO boilerplate. Define an interface extending JpaRepository<User, Long>; Spring generates the implementation at runtime. Method names like findByEmailAndActive(String email, boolean active) are parsed into JPQL queries automatically. @Query for custom JPQL or native SQL. Save, find, delete, page, sort — all provided without you writing a single line of query logic for common cases.
Key Facts
- @SpringBootApplication's component scan is bounded to the package it is in and its sub-packages. If you put the main class in com.example, only com.example.** is scanned. Beans in other packages are invisible unless explicitly imported — a common source of "No qualifying bean" errors.
- spring-boot-starter-* POMs are just dependency aggregators with no code. spring-boot-starter-web pulls in spring-webmvc, embedded Tomcat, Jackson, validation, and logging. The starter does no magic — the magic is in the auto-configuration JARs those dependencies include.
- The Actuator (spring-boot-starter-actuator) exposes /actuator/health, /actuator/metrics, /actuator/env, and dozens more management endpoints over HTTP (or JMX). In production, /actuator/health is what your load balancer pings to determine if a pod is ready.
- @Transactional works via a Spring AOP proxy wrapping your bean. The proxy intercepts method calls, opens a transaction before, and commits or rolls back after. Critical implication: calling a @Transactional method from within the same class bypasses the proxy and skips transaction management entirely — a very common bug.
- Spring Boot's DevTools (spring-boot-devtools) enables automatic restart when classpath files change. It uses two ClassLoaders: one for stable dependencies (rarely reloaded) and one for your code (reloaded on change). Faster than a full restart, but still slower than JVM HotSwap or JRebel.
Real-World Applications
Building REST APIs
@RestController + @RequestMapping defines endpoints. @RequestBody deserialises JSON to POJOs (via Jackson). @Valid triggers Bean Validation on @RequestBody. @ControllerAdvice + @ExceptionHandler centralises error handling. Spring Boot auto-configures Jackson, embedded Tomcat, and error responses — you write controller logic, not plumbing.
Database access with Spring Data JPA
Add spring-boot-starter-data-jpa + a database driver. Set spring.datasource.url in application.properties. Spring Boot auto-configures the DataSource, Hibernate EntityManagerFactory, and transaction manager. Define your @Entity classes and JpaRepository interfaces. Spring generates queries from method names at startup — zero boilerplate for standard CRUD and pagination.
Securing endpoints
Add spring-boot-starter-security. Auto-configuration secures all endpoints by default (HTTP Basic, form login). Override with a SecurityFilterChain @Bean: define which paths are public, which require ROLE_ADMIN, and configure JWT or OAuth2 resource server. Method-level security (@PreAuthorize("hasRole('ADMIN')")) guards individual service methods.
Frequently Asked Questions
What is the difference between Spring and Spring Boot?
Spring Framework is the core: IoC container, AOP, Spring MVC, Spring Data, Spring Security — powerful but requires manual configuration of every component. Spring Boot is a convention-over-configuration layer on top: it auto-configures Spring Framework components based on your classpath, provides embedded servers so you don't need an application server, and bundles everything into a single runnable JAR. You almost always use Spring Boot for new projects; "plain Spring" is rarely used directly anymore.
Why is constructor injection preferred over @Autowired on fields?
Three reasons: (1) It makes dependencies explicit — anyone reading the constructor knows exactly what the class needs. (2) It supports immutability — dependencies can be final. (3) It is easier to test — you can instantiate the class in a unit test by passing mock implementations directly, without a Spring context. Field injection hides dependencies and forces you to use Spring's reflection-based injection even in unit tests.
How does @Transactional actually work?
Spring wraps your bean in a JDK dynamic proxy (or CGLIB proxy for classes). When you call a @Transactional method, the proxy intercepts the call, asks the transaction manager to begin a transaction, calls your real method, then commits (or rolls back on exception). The catch: if class A calls its own @Transactional method internally (this.myMethod()), it bypasses the proxy and no transaction is started. Solution: inject a self-reference, use AopContext.currentProxy(), or restructure the code.
What is the Spring bean lifecycle?
Full lifecycle: (1) Instantiation — Spring calls the constructor. (2) Dependency injection — Spring injects @Autowired dependencies. (3) @PostConstruct — your initialization method runs. (4) Bean is ready — used by the application. (5) @PreDestroy — your cleanup method runs when the context shuts down. (6) Destruction. Use @PostConstruct for initialization logic that needs dependencies already injected (not the constructor). Use @PreDestroy to close resources, flush caches, etc.