Summary
Spring Boot is an opinionated framework built on top of Spring Framework that simplifies Java application development through auto-configuration, embedded servers, and starter dependencies. Following the principle of "convention over configuration," it enables rapid development of production-ready applications with minimal setup. This cheatsheet covers essential Spring Boot concepts including annotations, dependency injection, REST API development, data access with JPA, security implementation, testing strategies, monitoring with Actuator, and microservices patterns for technical interview preparation.
Spring Boot Basics
What is Spring Boot?
- Opinionated framework built on Spring Framework
- Convention over Configuration - minimal config needed
- Embedded servers (Tomcat, Jetty, Undertow)
- Auto-configuration based on classpath dependencies
- Production-ready features (metrics, health checks)
Key Features
- Starter Dependencies: Pre-configured dependency descriptors
- Auto-Configuration: Automatically configures beans based on classpath
- Embedded Server: No need for external application server
- Actuator: Production monitoring and management
- CLI: Command-line interface for quick prototyping
Project Structure
src/
├── main/
│ ├── java/
│ │ └── com/example/demo/
│ │ ├── DemoApplication.java # Main class
│ │ ├── controller/ # REST controllers
│ │ ├── service/ # Business logic
│ │ ├── repository/ # Data access
│ │ └── model/ # Entities/DTOs
│ └── resources/
│ ├── application.properties # Configuration
│ ├── static/ # Static resources
│ └── templates/ # View templates
└── test/ # Test classes
Core Annotations
Essential Annotations
@SpringBootApplication // Combines @Configuration + @EnableAutoConfiguration + @ComponentScan
@RestController // @Controller + @ResponseBody
@RequestMapping // Map HTTP requests to handler methods
@Component // Generic Spring-managed component
@Service // Business logic layer
@Repository // Data access layer
@Configuration // Java-based configuration
@Bean // Method produces a bean
Request Handling Annotations
@GetMapping("/users") // GET request
@PostMapping("/users") // POST request
@PutMapping("/users/{id}") // PUT request
@DeleteMapping("/users/{id}") // DELETE request
@PatchMapping("/users/{id}") // PATCH request
@PathVariable Long id // Extract from URL path
@RequestParam String name // Extract query parameter
@RequestBody User user // Extract request body
@RequestHeader String auth // Extract header value
Validation Annotations
@Valid // Trigger validation
@NotNull // Field cannot be null
@NotEmpty // Not null and not empty
@NotBlank // Not null, not empty, not whitespace
@Size(min=2, max=30) // String/Collection size
@Email // Valid email format
@Pattern(regexp="...") // Regex pattern
@Min(18) // Minimum numeric value
@Max(100) // Maximum numeric value
Dependency Injection & IoC
Injection Types
// 1. Constructor Injection (Recommended)
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}
// 2. Field Injection (Not recommended)
@Service
public class UserService {
@Autowired
private UserRepository repository;
}
// 3. Setter Injection
@Service
public class UserService {
private UserRepository repository;
@Autowired
public void setRepository(UserRepository repository) {
this.repository = repository;
}
}
Bean Scopes
@Component
@Scope("singleton") // Default - one instance (shared)
public class SingletonBean {}
@Component
@Scope("prototype") // New instance each time
public class PrototypeBean {}
@Component
@Scope("request") // One instance per HTTP request
public class RequestBean {}
@Component
@Scope("session") // One instance per HTTP session
public class SessionBean {}
Configuration
Application Properties
# application.properties
server.port=8080
spring.application.name=demo-app
# Database
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
# JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# Logging
logging.level.root=INFO
logging.level.com.example=DEBUG
Configuration Classes
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
@Profile("dev")
@Bean
public DataSource devDataSource() {
return new H2DataSource();
}
}
Profiles
// Activate profile: --spring.profiles.active=dev
@Component
@Profile("dev")
public class DevService implements MyService {}
@Component
@Profile("prod")
public class ProdService implements MyService {}
REST APIs
Basic REST Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User createUser(@Valid @RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id,
@Valid @RequestBody User user) {
user.setId(id);
return userService.save(user);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.deleteById(id);
}
}
Response Entity
// Custom response with status and headers
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity
.status(HttpStatus.OK)
.header("X-Custom-Header", "value")
.body(user);
}
Data Access (JPA)
Entity Definition
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(name = "full_name")
private String fullName;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Department department;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
Repository Layer
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Derived query methods
Optional<User> findByEmail(String email);
List<User> findByAgeGreaterThan(int age);
List<User> findByNameContainingIgnoreCase(String name);
// Custom JPQL query
@Query("SELECT u FROM User u WHERE u.email = ?1")
User findByEmailAddress(String email);
// Native SQL query
@Query(value = "SELECT * FROM users WHERE age > :age",
nativeQuery = true)
List<User> findUsersOlderThan(@Param("age") int age);
// Modifying queries
@Modifying
@Query("UPDATE User u SET u.active = false WHERE u.lastLogin < :date")
void deactivateInactiveUsers(@Param("date") LocalDate date);
}
Pagination and Sorting
// Controller
@GetMapping
public Page<User> getUsers(Pageable pageable) {
// GET /users?page=0&size=20&sort=name,asc
return userRepository.findAll(pageable);
}
// Custom pagination
PageRequest pageRequest = PageRequest.of(0, 10,
Sort.by("name").ascending());
Page<User> users = userRepository.findAll(pageRequest);
Exception Handling
Global Exception Handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
return new ErrorResponse("NOT_FOUND", ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return new ErrorResponse("VALIDATION_FAILED", errors);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGeneral(Exception ex) {
return new ErrorResponse("INTERNAL_ERROR", "An error occurred");
}
}
Custom Exceptions
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Security
Basic Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JWT Authentication
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 864000000))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public String extractUsername(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
Testing
Unit Testing
@SpringBootTest
class UserServiceTest {
@MockBean
private UserRepository userRepository;
@Autowired
private UserService userService;
@Test
void testFindById() {
// Given
User user = new User(1L, "John", "john@example.com");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
// When
User found = userService.findById(1L);
// Then
assertThat(found.getName()).isEqualTo("John");
}
}
Integration Testing
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testCreateUser() throws Exception {
String userJson = "{\"name\":\"John\",\"email\":\"john@example.com\"}";
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(userJson))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("John"));
}
}
Repository Testing
@DataJpaTest
class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
void testFindByEmail() {
// Given
User user = new User("John", "john@example.com");
entityManager.persistAndFlush(user);
// When
Optional<User> found = userRepository.findByEmail("john@example.com");
// Then
assertThat(found).isPresent();
assertThat(found.get().getName()).isEqualTo("John");
}
}
Actuator & Monitoring
Enable Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator Configuration
# Expose endpoints
management.endpoints.web.exposure.include=health,info,metrics,env
management.endpoint.health.show-details=always
# Custom info
info.app.name=Demo Application
info.app.version=1.0.0
Custom Health Indicator
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
if (conn.isValid(1000)) {
return Health.up()
.withDetail("database", "Available")
.build();
}
} catch (Exception e) {
return Health.down(e).build();
}
return Health.down().build();
}
}
Best Practices
1. Use Constructor Injection
// Good
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
2. Follow REST Conventions
- Use proper HTTP methods (GET, POST, PUT, DELETE)
- Return appropriate status codes
- Use plural nouns for resources (/users, not /user)
3. Implement Proper Exception Handling
- Use @RestControllerAdvice for global handling
- Return consistent error responses
- Log exceptions appropriately
4. Use DTOs for API Responses
// Don't expose entities directly
public class UserDTO {
private Long id;
private String name;
private String email;
// Exclude sensitive fields like password
}
5. Implement Validation
- Use Bean Validation annotations
- Validate at controller level with @Valid
- Create custom validators when needed
6. Use Transactions Properly
@Service
@Transactional
public class UserService {
@Transactional(readOnly = true)
public List<User> findAll() { }
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createNewTransaction() { }
}
7. Implement Caching
@Service
public class UserService {
@Cacheable("users")
public User findById(Long id) { }
@CacheEvict("users")
public void deleteUser(Long id) { }
}
8. Use Profiles for Environments
- dev, test, prod profiles
- Environment-specific configurations
- Use @Profile annotation
9. Implement Logging
@Slf4j // Lombok
@Service
public class UserService {
public User findById(Long id) {
log.debug("Finding user by id: {}", id);
// ...
}
}
10. Write Tests
- Unit tests for services
- Integration tests for controllers
- Repository tests with @DataJpaTest
Key Concepts & Comparisons
Spring Boot vs Spring Framework
| Aspect | Spring Framework | Spring Boot | Benefits |
|---|---|---|---|
| Configuration | Manual XML/Java config | Auto-configuration | 80% less configuration code |
| Server | External server deployment | Embedded server | Deploy as JAR, no server setup |
| Dependencies | Manual dependency management | Starter POMs | Simplified dependency management |
| Production Features | Manual setup | Built-in (Actuator) | Production-ready out of the box |
| Testing | Manual test configuration | Test starters | Faster test development |
| Development Speed | Slower setup | Rapid development | Focus on business logic |
Bean Scopes Deep Dive
| Scope | Lifecycle | Thread Safety | Use Case | Memory Impact |
|---|---|---|---|---|
| Singleton | One per container | Not guaranteed | Stateless services, repositories | Low - single instance |
| Prototype | New per request | Thread-safe | Stateful objects, DTOs | High - multiple instances |
| Request | One per HTTP request | Thread-safe | Web request data | Medium - per request |
| Session | One per HTTP session | Thread-safe | User session data | Medium - per session |
| Application | One per ServletContext | Not guaranteed | Application-wide cache | Low - single instance |
Dependency Injection Types
| Type | Implementation | Pros | Cons | Best Practice |
|---|---|---|---|---|
| Constructor | Via constructor | Immutable, testable, required deps clear | Verbose with many deps | ✅ Recommended |
| Field | @Autowired on field |
Less code | Hard to test, hidden dependencies | ❌ Avoid |
| Setter | Via setter method | Optional dependencies | Mutable, unclear requirements | ⚠️ Use sparingly |
Auto-Configuration Conditions
| Annotation | Condition | Example Use Case |
|---|---|---|
| @ConditionalOnClass | Class present in classpath | Enable if dependency exists |
| @ConditionalOnMissingBean | Bean not already defined | Default bean configuration |
| @ConditionalOnProperty | Property has specific value | Feature toggles |
| @ConditionalOnWebApplication | Web environment | Web-specific beans |
| @ConditionalOnResource | Resource exists | Load config if file present |
Transaction Propagation Levels
| Level | Behavior | Use Case | Transaction Boundary |
|---|---|---|---|
| REQUIRED | Join existing or create new | Default behavior | Participates in outer transaction |
| REQUIRES_NEW | Always create new | Independent operations | Suspends outer transaction |
| SUPPORTS | Use if exists, else none | Read operations | Flexible participation |
| MANDATORY | Must have existing | Enforce transactional context | Throws exception if none |
| NOT_SUPPORTED | Execute without transaction | Non-transactional operations | Suspends if exists |
| NEVER | Must not have transaction | Ensure non-transactional | Throws exception if exists |
Spring Boot Starters Comparison
| Starter | Dependencies Included | Use Case | Auto-Configured |
|---|---|---|---|
| spring-boot-starter-web | Spring MVC, Tomcat, Jackson | REST APIs, web apps | DispatcherServlet, ErrorMvcAutoConfiguration |
| spring-boot-starter-data-jpa | Hibernate, Spring Data JPA | Database access | DataSource, EntityManagerFactory |
| spring-boot-starter-security | Spring Security | Authentication/Authorization | SecurityFilterChain, UserDetailsService |
| spring-boot-starter-test | JUnit, Mockito, AssertJ | Testing | MockMvc, TestRestTemplate |
| spring-boot-starter-actuator | Micrometer, Health indicators | Production monitoring | Endpoints, metrics |
Exception Handling Strategies
| Strategy | Scope | Implementation | Use Case |
|---|---|---|---|
| @ExceptionHandler | Controller-specific | Method in controller | Local error handling |
| @RestControllerAdvice | Global | Separate class | Application-wide handling |
| ResponseStatusException | Throw anywhere | Direct exception | Simple status codes |
| Custom exceptions | Domain-specific | Extend RuntimeException | Business logic errors |
Caching Providers
| Provider | Performance | Features | Configuration |
|---|---|---|---|
| ConcurrentHashMap | Very Fast | Simple, in-memory | Default, no config |
| Ehcache | Fast | TTL, disk storage | XML or Java config |
| Redis | Fast | Distributed, persistent | Connection properties |
| Hazelcast | Fast | Distributed, clustering | Network config |
| Caffeine | Very Fast | Advanced features | Programmatic |
Security Authentication Methods
| Method | Complexity | Stateless | Use Case | Implementation |
|---|---|---|---|---|
| Basic Auth | Low | Yes | Development, internal APIs | Username/password in header |
| JWT | Medium | Yes | REST APIs, microservices | Token-based authentication |
| OAuth2 | High | Yes | Third-party integration | Authorization server |
| Form Login | Low | No | Traditional web apps | Session-based |
| API Key | Low | Yes | Service-to-service | Custom header/parameter |
Testing Annotations
| Annotation | Test Type | Loaded Components | Use Case |
|---|---|---|---|
| @SpringBootTest | Integration | Full context | End-to-end testing |
| @WebMvcTest | Unit | Web layer only | Controller testing |
| @DataJpaTest | Unit | JPA components | Repository testing |
| @RestClientTest | Unit | REST clients | External API testing |
| @JsonTest | Unit | JSON mapping | Serialization testing |
Performance Optimization Techniques
| Technique | Impact | Implementation | Trade-off |
|---|---|---|---|
| Connection Pooling | High | HikariCP (default) | Memory vs connections |
| Caching | High | @Cacheable annotations | Memory vs freshness |
| Lazy Loading | Medium | JPA fetch strategies | N+1 queries risk |
| Async Processing | High | @Async methods | Complexity |
| Response Compression | Medium | Server configuration | CPU vs bandwidth |
Monitoring with Actuator
| Endpoint | Purpose | Default Exposure | Sensitive |
|---|---|---|---|
| /health | Application health | Yes | Configurable |
| /info | Application info | Yes | No |
| /metrics | Application metrics | No | Yes |
| /env | Environment properties | No | Yes |
| /loggers | Logger configuration | No | Yes |
| /threaddump | Thread information | No | Yes |
Profile-Based Configuration
| Profile | Use Case | Activation | Configuration |
|---|---|---|---|
| dev | Development | --spring.profiles.active=dev |
Debug logging, H2 database |
| test | Testing | @ActiveProfiles("test") | Test data, mocks |
| prod | Production | Environment variable | Real database, security |
| local | Local development | IDE configuration | Local services |
Common Interview Topics Summary
Core Concepts
- Auto-configuration mechanism using @Conditional annotations
- Starter dependencies and how they simplify development
- @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
- Embedded server advantages and configuration
Dependency Injection
- Constructor injection preferred for required dependencies
- Bean scopes and their appropriate use cases
- @Qualifier for multiple beans of same type
- Circular dependency resolution strategies
Data Access
- Spring Data JPA repository pattern
- Transaction management with @Transactional
- Query methods and @Query annotations
- Pagination and sorting implementation
REST API Development
- RESTful design principles
- Request mapping annotations
- Response entity and status codes
- Exception handling strategies
Security
- Spring Security filter chain
- Authentication vs Authorization
- JWT implementation
- Method-level security
Testing
- Test slices for targeted testing
- MockBean vs Mock
- Integration testing strategies
- Test containers for database testing
Performance
- Caching strategies and providers
- Connection pool configuration
- Async processing benefits
- JPA optimization techniques
Microservices
- Spring Cloud components
- Service discovery patterns
- Circuit breaker implementation
- Configuration management
Production Features
- Actuator endpoints and monitoring
- Health indicators
- Metrics collection
- Log aggregation
Best Practices
- Proper exception handling
- Configuration externalization
- Profile management
- Security considerations
Quick Reference
Maven Dependencies
<!-- Core -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Application Entry Point
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Common Properties
# Server
server.port=8080
server.servlet.context-path=/api
# Database
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
# Logging
logging.level.root=INFO
logging.pattern.console=%d{HH:mm:ss} %-5level %logger{36} - %msg%n
# Jackson
spring.jackson.serialization.write-dates-as-timestamps=false
spring.jackson.default-property-inclusion=non_null
Remember for Interviews
- Understand the basics thoroughly - IoC, DI, Bean lifecycle
- Know the annotations - What they do and when to use them
- Practice coding - Be ready to write REST APIs from scratch
- Understand the architecture - MVC pattern, layered architecture
- Know best practices - SOLID principles, clean code
- Be familiar with testing - Unit and integration tests
- Understand security basics - Authentication vs Authorization
- Know about microservices - Basic concepts and Spring Cloud
- Performance considerations - Caching, connection pooling
- Stay updated - Spring Boot 3.x features, Java 17+ support
Good luck with your interview! 🚀