Spring Boot Fundamentals

Spring Boot is the dominant Java application framework. It packages Spring Framework with sensible defaults, embedded servers, and dependency starters that turn "build a web application" from a hundred lines of XML into a single annotation. Most modern Java backend code runs on Spring Boot or something close to it.

This page covers the core concepts — the parts you need to understand to use Spring Boot effectively, not the encyclopedic catalog of every annotation.

What Spring Boot adds to Spring

Spring Framework provides:

- IoC container (managed beans)

- Dependency injection

- Aspect-oriented programming

- Spring MVC (web framework)

- Spring Data (data access abstraction)

Spring Boot adds:

- Auto-configuration based on classpath

- Starter dependencies (curated transitive dependencies)

- Embedded servers (Tomcat by default; Jetty, Undertow, Netty available)

- Production-ready features (metrics, health checks, configuration externalization)

- Convention-over-configuration defaults

The trade-off: Spring Boot's "magic" auto-configuration is convenient but can be opaque when something goes wrong. Understanding what Spring Boot is doing is necessary for non-trivial debugging.

The application class

A Spring Boot application starts from a class with `@SpringBootApplication`:

```java

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

```

`@SpringBootApplication` combines:

- `@SpringBootConfiguration` (Spring Boot's `@Configuration`)

- `@EnableAutoConfiguration` (the magic)

- `@ComponentScan` (find beans starting from this package)

By convention, `@SpringBootApplication` lives at the top of the package hierarchy; component scanning finds everything underneath.

Beans

A Spring "bean" is an object managed by the IoC container. Three ways to declare:

`@Component` family on a class

```java

@Component

public class OrderService { /* ... */ }

@Service // semantic alias for @Component

@Repository // for data access

@Controller // for web controllers

@RestController // controller + @ResponseBody

```

The container finds these via `@ComponentScan`. Annotated classes become beans automatically.

`@Bean` on methods in a `@Configuration` class

```java

@Configuration

public class AppConfig {

@Bean

public DataSource dataSource() {

return new HikariDataSource();

}

}

```

Useful for creating beans from third-party code (no annotations available) or for conditional bean creation.

`@SpringBootApplication` itself

The application class is also a `@Configuration` class; you can declare `@Bean` methods directly on it for small applications.

Dependency injection

Inject dependencies via constructor (preferred):

```java

@Service

public class OrderService {

private final OrderRepository repository;

private final NotificationService notifications;

public OrderService(OrderRepository repository, NotificationService notifications) {

this.repository = repository;

this.notifications = notifications;

}

}

```

The container finds the matching beans and passes them in. `final` fields make the dependencies clearly required.

Field injection (`@Autowired` on a field) works but is discouraged: harder to test, hides dependencies, prevents `final` fields.

Auto-configuration

The signature feature. Based on what's on the classpath, Spring Boot configures things automatically:

- Classpath has `spring-boot-starter-web`? Configure embedded Tomcat, Spring MVC, Jackson.

- Classpath has `spring-boot-starter-data-jpa`? Configure Hibernate, transaction management, JPA repositories.

- Classpath has `spring-boot-starter-actuator`? Configure health endpoints, metrics, info.

Each starter brings a transitive dependency tree plus the auto-configuration classes that wire it up.

You can:

- Override defaults via `application.properties` / `application.yaml`

- Provide custom `@Bean` methods that Spring Boot uses instead of its defaults

- Disable specific auto-configurations

Configuration

External configuration via `application.properties`:

```properties

server.port=8080

spring.datasource.url=jdbc:postgresql://localhost/mydb

spring.datasource.username=app

logging.level.org.springframework=INFO

```

Inject configuration with `@Value` (simple) or `@ConfigurationProperties` (typed):

```java

@ConfigurationProperties(prefix = "app.email")

public record EmailConfig(String host, int port, String username, String password) {}

```

Configuration profiles allow environment-specific settings:

```

application.properties

application-dev.properties

application-prod.properties

```

Activate a profile with `--spring.profiles.active=prod`.

Web controllers

REST endpoints with `@RestController`:

```java

@RestController

@RequestMapping("/api/orders")

public class OrderController {

private final OrderService service;

public OrderController(OrderService service) {

this.service = service;

}

@GetMapping("/{id}")

public Order get(@PathVariable String id) {

return service.findById(id);

}

@PostMapping

public Order create(@RequestBody @Valid CreateOrderRequest request) {

return service.create(request);

}

}

```

Methods become endpoints; parameters are bound from path, query, headers, or body.

Data access

`@Repository` interfaces extending `JpaRepository`:

```java

public interface OrderRepository extends JpaRepository<Order, String> {

List<Order> findByStatus(OrderStatus status);

}

```

Spring Data implements the interface at runtime. Method names are parsed into queries (`findByStatus` → `WHERE status = ?`).

For complex queries, `@Query` annotations or QueryDSL.

Testing

`@SpringBootTest` loads the full application context:

```java

@SpringBootTest

class OrderServiceTest {

@Autowired

OrderService service;

@Test

void shouldCreateOrder() {

Order order = service.create(...);

assertThat(order).isNotNull();

}

}

```

For faster tests, slices like `@WebMvcTest` (controller layer only) or `@DataJpaTest` (data layer only) load a smaller context.

`@MockBean` replaces a real bean with a Mockito mock for tests.

What to learn next

The fundamentals above cover ~80% of typical Spring Boot usage. Beyond that:

- **Spring Security** for authentication/authorization

- **Spring Data JPA / Spring Data MongoDB** for specific data stores

- **Spring Actuator** for production endpoints

- **Spring Cloud** for distributed systems patterns (config, service discovery, circuit breakers)

- **Spring Reactor / WebFlux** for reactive programming

Common failure patterns

- **Field injection.** Constructor injection is easier to test and clearer about dependencies.

- **Tangled bean dependencies.** Circular dependencies (A depends on B depends on A) are usually a design error.

- **Heavy auto-configuration with no understanding.** When something doesn't work, you need to know what Spring Boot configured to debug.

- **`@SpringBootTest` for everything.** Slow; use slices when possible.

- **Hard-coded configuration.** Use `application.properties`; profile-specific files; environment variables.

- **Treating auto-configuration as immutable.** It's not — you can override anything with explicit beans.

Further Reading

- [MavenMultiModuleProjects](MavenMultiModuleProjects) — Spring Boot project structure

- [JpaAndHibernatePatterns](JpaAndHibernatePatterns) — Data layer underlying Spring Data JPA

- [ServletArchitectureDeepDive](ServletArchitectureDeepDive) — What Spring MVC sits on

- [JavaCollectionsFramework](JavaCollectionsFramework) — Common return types from Spring data

- [Java Hub](JavaHub) — Cluster index