Spring Boot
Spring Boot
| Spring |
Spring Boot |
| Spring is an open-source lightweight framework widely used to develop enterprise applications. |
Spring Boot is built on top of the conventional spring framework, widely used to develop REST APIs. |
| The most important feature of the Spring Framework is dependency injection. |
The most important feature of the Spring Boot is Autoconfiguration. |
| It helps to create a loosely coupled application. |
It helps to create a stand-alone application. |
| To run the Spring application, we need to set the server explicitly. |
Spring Boot provides embedded servers such as Tomcat and Jetty etc. |
| To run the Spring application, a deployment descriptor is required. |
There is no requirement for a deployment descriptor. |
| To create a Spring application, the developers write lots of code. |
It reduces the lines of code. |
| It doesn’t provide support for the in-memory database. |
It provides support for the in-memory database such as H2. |
| Developers need to write boilerplate code for smaller tasks. |
In Spring Boot, there is reduction in boilerplate code. |
| Developers have to define dependencies manually in the pom.xml file. |
pom.xml file internally handles the required dependencies. |
Core Concepts
IoC & Dependency Injection
- Inversion of Control (IoC): Spring manages object creation and lifecycles; beans are wired at runtime
- Dependency Injection: Dependencies passed via constructor, setter, or field injection
- Bean: Managed Spring object; scope: singleton (default, one per context), prototype (new each time), request/session (web)
Spring Boot Advantages
- Auto-configuration: Detects classpath & creates beans automatically (e.g.,
@EnableAutoConfiguration or @SpringBootApplication)
- Embedded servers: Tomcat/Jetty/Undertow bundled; no WAR deployment needed
- Starter POM: Curated dependency sets (
spring-boot-starter-web, etc.) eliminate version conflicts
- Externalized config: Properties from
application.yml, env vars, command-line args (in precedence order)
- Actuator:
/actuator/health, /metrics, /loggers for monitoring
For advanced topics (DI patterns, bean lifecycle, application lifecycle, profiles, multi-db, circular dependency), see Spring Boot Advanced.
Spring Boot Starters
Spring Boot Starters are pre-configured dependency descriptors that simplify Maven/Gradle configuration. They bundle compatible versions and eliminate version conflicts.
Common Starters
| Starter |
Purpose |
Includes |
spring-boot-starter-web |
REST APIs, MVC |
Spring Web, Tomcat, JSON serialization |
spring-boot-starter-data-jpa |
Database access with ORM |
Spring Data JPA, Hibernate, connection pooling |
spring-boot-starter-security |
Authentication & authorization |
Spring Security, password encoding |
spring-boot-starter-actuator |
Monitoring & metrics |
Health endpoints, metrics, audit events |
spring-boot-starter-validation |
Bean validation |
JSR-380 validators |
spring-boot-starter-logging |
Structured logging |
SLF4J, Logback |
spring-boot-starter-cache |
Caching support |
Cache abstraction, no default implementation |
spring-boot-starter-aop |
Aspect-oriented programming |
Spring AOP, AspectJ |
spring-boot-starter-batch |
Batch processing |
Spring Batch framework |
spring-boot-starter-amqp |
Message broker (RabbitMQ) |
Spring AMQP, RabbitMQ client |
spring-boot-starter-data-redis |
Redis cache/session |
Spring Data Redis, Jedis/Lettuce |
spring-boot-starter-webflux |
Reactive (non-blocking) |
Reactor, Netty, Spring WebFlux |
Example: pom.xml
<dependencies>
<!-- Starter automatically includes spring-web, tomcat, jackson -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Starter includes spring-data-jpa, hibernate, h2 (test) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL driver (not included in starter) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
Bill of Materials (BOM)
Spring Boot manages versions automatically; no need to specify version for starter POMs:
<!-- ❌ Don't do this -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.0</version> <!-- Wrong: Spring manages this -->
</dependency>
<!-- ✅ Do this -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Version inherited from parent POM -->
</dependency>
Parent POM (usually in pom.xml):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
Common Annotations
Application Setup
| Annotation |
Purpose |
Example |
@SpringBootApplication |
Combines @Configuration, @ComponentScan, @EnableAutoConfiguration |
Main class |
@Configuration |
Marks class as bean factory (like XML <beans>) |
Bean definitions |
@Bean |
Method-level; returns managed object |
@Bean public MyService service() {} |
@ComponentScan |
Scans packages for @Component, @Service, etc. |
Base path for auto-discovery |
@EnableAutoConfiguration |
Activates auto-config; rarely used (in @SpringBootApplication) |
Config class |
Stereotypes (Component Registration)
| Annotation |
Purpose |
@Component |
Generic managed bean |
@Service |
Business logic layer |
@Repository |
Data access layer (enables exception translation, transaction support) |
@Controller |
Web layer; handles HTTP requests |
@RestController |
Like @Controller + @ResponseBody (returns JSON/XML, not views) |
Dependency Injection
// Constructor injection (preferred - immutable, testable)
@Service
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) {
this.repo = repo;
}
}
// Setter injection
@Service
public class OrderService {
private PaymentGateway gateway;
@Autowired
public void setGateway(PaymentGateway gateway) {
this.gateway = gateway;
}
}
// Field injection (discouraged - hard to test, hides dependencies)
@Service
public class ReportService {
@Autowired
private ReportRepository repo;
}
// Qualifier - pick specific bean when multiple implementations exist
@Autowired
@Qualifier("primaryDB")
private DataSource dataSource;
// Primary - default bean when multiple of same type (preferred over @Qualifier)
@Component
public class PrimaryDataSourceConfig {
@Bean
@Primary // Used by default
public DataSource primaryDataSource() {
return new HikariDataSource();
}
@Bean("secondaryDB")
public DataSource secondaryDataSource() {
return new HikariDataSource();
}
}
// Usage: no qualifier needed; @Primary is injected
@Service
public class UserService {
@Autowired
private DataSource dataSource; // Gets primaryDataSource (marked @Primary)
}
// Override primary if needed
@Service
public class ReportService {
@Autowired
@Qualifier("secondaryDB")
private DataSource dataSource; // Explicitly uses secondaryDB
}
// Optional dependency
@Autowired(required = false)
private Logger logger;
Request Handling (Spring MVC)
| Annotation |
Purpose |
@GetMapping |
GET request; shorthand for @RequestMapping(method=GET) |
@PostMapping |
POST request |
@PutMapping |
PUT request |
@DeleteMapping |
DELETE request |
@PatchMapping |
PATCH request (partial update) |
@RequestParam |
Query/form parameter: @RequestParam String name |
@PathVariable |
URL path segment: @GetMapping("/user/{id}") with @PathVariable Long id |
@RequestBody |
JSON/XML body deserialized to object |
@ResponseBody |
Return value serialized to JSON/XML (implicit in @RestController) |
@RequestHeader |
HTTP header: @RequestHeader String authorization |
@CookieValue |
Cookie parameter |
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }
@PostMapping
public User create(@RequestBody User user) { ... }
@PutMapping("/{id}")
public User update(@PathVariable Long id, @RequestBody User user) { ... }
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) { ... }
@GetMapping
public List<User> list(@RequestParam(defaultValue = "0") int page) { ... }
}
Configuration & Properties
| Annotation |
Purpose |
@ConfigurationProperties |
Bind config to object (type-safe); e.g., @ConfigurationProperties(prefix="app.db") maps app.db.host, app.db.port to fields |
@Value |
Inject single property: @Value("${app.name}") |
@Profile |
Conditional bean/config per environment: @Profile("prod"), @Profile("!prod") |
@Conditional |
Complex condition: @Conditional(MyCondition.class) |
@EnableConfigurationProperties |
Register @ConfigurationProperties classes |
@Configuration
@ConfigurationProperties(prefix = "app.database")
public class DatabaseConfig {
private String host; // app.database.host
private int port; // app.database.port
private String username; // app.database.username
}
// Use in beans
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource(DatabaseConfig config) {
// Build DataSource from config
}
}
Exception Handling
| Annotation |
Purpose |
@ControllerAdvice |
Global exception handler; catches exceptions from all controllers |
@ExceptionHandler |
Method-level; handles specific exception type |
@ResponseStatus |
HTTP status code for exception response |
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(UserNotFoundException ex) {
return new ErrorResponse(ex.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGeneric(Exception ex) {
return new ErrorResponse("Internal error");
}
}
Transactions
@Service
public class OrderService {
// ACID: all-or-nothing. If exception, rollback automatically
@Transactional
public void createOrder(Order order) {
orderRepo.save(order);
paymentGateway.charge(order.getAmount()); // If fails, both rolled back
}
// Read-only (no writes expected; optimization)
@Transactional(readOnly = true)
public List<Order> getOrders() { ... }
// Propagation: REQUIRED (default), REQUIRES_NEW, SUPPORTS, etc.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void audit(String action) { ... }
}
Other Useful Annotations
| Annotation |
Purpose |
@Async |
Run method in thread pool (requires @EnableAsync) |
@Scheduled |
Cron/fixed-delay task (requires @EnableScheduling) |
@Validated |
Enable bean validation (JSR-380) |
@Valid |
Trigger validation on parameter/field |
@NotNull, @NotEmpty, @Email, etc. |
Validation constraints |
@CrossOrigin |
Allow CORS from specified origins |
@PreAuthorize, @PostAuthorize |
Security checks (Spring Security) |
Configuration Files
Properties Precedence (highest to lowest)
- Command-line args:
java -jar app.jar --server.port=9000
- System properties:
-Dkey=value
- Environment variables:
SPRING_APPLICATION_NAME=myapp
application.yml (active profile overrides base): application-prod.yml
application-default.properties
# application.yml
spring:
application:
name: my-service
profiles:
active: dev
datasource:
url: jdbc:mysql://localhost:3306/db
username: root
jpa:
hibernate:
ddl-auto: update
jackson:
serialization:
write-dates-as-timestamps: false
server:
port: 8080
servlet:
context-path: /api
app:
name: My App
version: 1.0.0
Profiles
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
jpa:
show-sql: true
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/db
jpa:
show-sql: false
Activate: java -jar app.jar --spring.profiles.active=prod