Spring Boot in a Nutshell
Spring Boot builds on Spring to let you create production-grade applications with minimal configuration. Annotations drive most of the functionality – component scanning, dependency injection, configuration, web endpoints, persistence, security, caching, scheduling, and testing. Read more about them in this blog.
Application Bootstrap & Configuration
@SpringBootApplication
What it is: Convenience annotation that combines @Configuration, @EnableAutoConfiguration, and @ComponentScan.
Use when: Bootstrapping your application.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DcepApplication {
public static void main(String[] args) {
SpringApplication.run(DcepApplication.class, args);
}
}
@Configuration+@Bean
What they do: Define configuration classes and factory methods for Spring-managed beans.
Use when: You need fine-grained control over bean creation or third‑party library wiring.
import org.springframework.context.annotation.*;
@Configuration
public class AppConfig {
@Bean
@Primary // preferred bean if multiple candidates exist
public ObjectMapper objectMapper() {
return new ObjectMapper().findAndRegisterModules();
}
}
@Value and @ConfigurationProperties
What they do: Bind properties to fields.
Use when: Injecting configuration values (URLs, timeouts, credentials).
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ExternalServiceProps {
@Value("${service.endpoint.url}")
private String endpointUrl;
}
// Prefer strongly-typed binding:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "service")
public class ServiceProperties {
private String endpointUrl;
private int timeout;
// getters/setters
}
@Profile and Conditional Annotations
What they do: Activate beans based on environment or conditions.
Use when: Different behavior for dev, test, prod.
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
@Profile("dev")
public class DevEmailService implements EmailService { /* ... */ }
import org.springframework.boot.autoconfigure.condition.*;
@Configuration
public class FeatureToggleConfig {
@Bean
@ConditionalOnProperty(name = "feature.x.enabled", havingValue = "true")
public FeatureX featureX() { return new FeatureX(); }
@Bean
@ConditionalOnMissingBean
public DefaultFeature defaultFeature() { return new DefaultFeature(); }
}
Component Model & Dependency Injection
@Component, @Service, @Repository, @Controller, @RestController
What they do: Mark classes for component scanning and define their roles.
Use when: Structuring layers and enabling DI.
import org.springframework.stereotype.*;
@Service
public class PaymentService { /* business logic */ }
@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> { }
@RestController
@RequestMapping("/api/payments")
public class PaymentController { /* endpoints */ }
@RestController = @Controller + @ResponseBody for JSON responses.
@Autowired, @Qualifier, @Primary
What they do: Inject dependencies and disambiguate between multiple candidates.
Use when: You have multiple beans of same type.
@Service
public class ReportService {
private final ReportGenerator generator;
@Autowired
private final PdfService pdfService;
public ReportService(@Qualifier("pdfReportGenerator") ReportGenerator generator) {
this.generator = generator;
}
}
Web & REST (Spring MVC)
@RequestMapping,@GetMapping,@PostMapping,@PutMapping, @DeleteMapping
What they do: Map HTTP requests to handler methods.
Use when: Defining REST endpoints.
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public UserDto get(@PathVariable Long id) { /*...*/ }
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDto create(@Valid @RequestBody CreateUserRequest req) { /*...*/ }
}
@PathVariable, @RequestParam, @RequestBody, @ResponseStatus
What they do: Bind parts of the request to method parameters and control response status.
@GetMapping("/list/{type}")
public List<UserDto> list(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@PathVariable(value="type") String type) { /*...*/ }
@ControllerAdvice + @ExceptionHandler
What they do: Centralized exception handling across controllers.
Use when: Returning uniform error format.
import org.springframework.web.bind.annotation.*;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResponse handleNotFound(EntityNotFoundException ex) {
return new ErrorResponse("NOT_FOUND", ex.getMessage());
}
}
@CrossOrigin
What it does: Enable CORS on controllers or methods.
Use when: Frontend hosted on a different origin.
@CrossOrigin(origins = "https://app.example.com")
@GetMapping("/public")
public InfoDto publicInfo() { /*...*/ }
Validation (Bean Validation / Jakarta Validation)
@Valid and constraint annotations (@NotNull, @Size, @Email, etc.)
What they do: Validate request payloads and beans.
Use when: Input validation at the API boundary.
import jakarta.validation.constraints.*;
public record CreateUserRequest(
@NotBlank String username,
@Email String email,
@Size(min = 8) String password
) {}
@PostMapping("/users")
public UserDto create(@Valid @RequestBody CreateUserRequest req) { /*...*/ }
Data & Persistence (Spring Data JPA)
JPA Entity Annotations: @Entity, @Table, @Id, @GeneratedValue, @Column
What they do: Map classes to database tables.
Use when: Persisting domain models.
import jakarta.persistence.*;
@Entity
@Table(name = "payments")
public class Payment {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long amount;
// relationships, getters, setters
}
Relationship Annotations: @ManyToOne, @OneToMany, @OneToOne, @ManyToMany, @JoinColumn
What they do: Define associations between entities.
@Entity
public class Order {
@Id @GeneratedValue private Long id;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderLine> lines = new ArrayList<>();
}
Spring Data Repositories: @Repository, CrudRepository/JpaRepository
What they do: Auto-implement common CRUD operations; query derivation by method name.
@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> {
List<Payment> findByAmountGreaterThan(long minAmount);
}
@Transactional
What it does: Demarcate transactional boundaries.
Use when: Methods that read/write the database.
import org.springframework.transaction.annotation.Transactional;
@Service
public class PaymentService {
@Transactional
public Payment createPayment(Payment p) { return repo.save(p); }
@Transactional(readOnly = true)
public Optional<Payment> find(Long id) { return repo.findById(id); }
}
Caching
@EnableCaching, @Cacheable, @CachePut, @CacheEvict
What they do: Enable cache abstraction and control caching behavior.
Use when: Improving performance of repeated reads.
import org.springframework.cache.annotation.*;
@Configuration
@EnableCaching
public class CacheConfig { /* cache manager setup if needed */ }
@Service
public class ProductService {
@Cacheable(value = "productById", key = "#id")
public Product getProduct(Long id) { return repo.findById(id).orElseThrow(); }
@CachePut(value = "productById", key = "#product.id")
public Product update(Product product) { return repo.save(product); }
@CacheEvict(value = "productById", key = "#id")
public void delete(Long id) { repo.deleteById(id); }
}
Asynchronous & Scheduling
@EnableAsync + @Async
What they do: Run methods in a separate thread pool.
Use when: Sending emails, calling external APIs, heavy computations that shouldn’t block.
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig { }
@Service
public class NotificationService {
@Async
public CompletableFuture<Void> sendEmailAsync(String to) { /*...*/ return CompletableFuture.completedFuture(null); }
}
@EnableScheduling + @Scheduled
What they do: Run methods on a schedule (cron, fixed rate, fixed delay).
Use when: Cleanups, sync jobs, reporting.
import org.springframework.scheduling.annotation.*;
@Configuration
@EnableScheduling
public class SchedulerConfig { }
@Component
public class DailyJob {
@Scheduled(cron = "0 0 2 * * *") // every day at 02:00
public void runNightlyCleanup() { /*...*/ }
}
Security (Spring Security)
@EnableWebSecurity and Method Security (@EnableMethodSecurity / @PreAuthorize)
What they do: Configure web security and guard methods with role/permission checks.
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableWebSecurity
public class SecurityConfig { /* HttpSecurity configuration */ }
import org.springframework.security.access.prepost.PreAuthorize;
@Service
public class AdminService {
@PreAuthorize("hasRole('ADMIN')")
public void performAdminTask() { /*...*/ }
}
In Spring Security 6+, use @EnableMethodSecurity (supersedes @EnableGlobalMethodSecurity).
Observability
Spring Boot Actuator is largely auto-configured, but you’ll often use:
@Endpoint (advanced), or rely on auto-configured endpoints
What it does: Create custom actuator endpoints.
Use when: Exposing health or diagnostics specific to your domain.
import org.springframework.boot.actuate.endpoint.annotation.*;
@Endpoint(id = "customInfo")
@Component
public class CustomInfoEndpoint {
@ReadOperation
public Map<String, Object> info() { return Map.of("build", "v1.2.3"); }
}
Testing
@SpringBootTest
What it does: Load the full application context for integration tests.
Use when: End-to-end or component integration testing.
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;
@SpringBootTest
class AppIntegrationTest {
@Test void contextLoads() { }
}
Slice Tests: @WebMvcTest, @DataJpaTest, @MockBean
What they do: Load a focused part of the context for fast tests.
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@WebMvcTest(UserController.class)
class UserControllerTest {
@MockBean private UserService userService;
// use MockMvc to test endpoints
}
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@DataJpaTest
class PaymentRepositoryTest {
// repository tests with in-memory DB
}
Day-to-Day Best Practices
- Keep Controllers Thin: Use
@Servicefor business logic;@RestControlleronly wires I/O. - Validate Inputs: Use
@Valid+ constraint annotations in request DTOs. - Centralize Errors:
@ControllerAdvice+@ExceptionHandlerfor consistent API responses. - Transactions at Service Layer: Prefer
@Transactionalon service methods, not repositories. - Use ConfigurationProperties: Typed config beats scattered
@Valuestrings. - Guard with Profiles: Use
@Profileto separate dev/test/prod bean behavior. - Cache Read-Heavy Methods:
@Cacheablefor hot lookups; remember eviction on writes. - Schedule & Async Thoughtfully: Always consider thread pools and retries for
@Asyncand@Scheduled. - Secure at Method Level:
@PreAuthorizekeeps services safe even if endpoints change. - Write Focused Tests: Use slice testing (
@WebMvcTest,@DataJpaTest) for speed; full@SpringBootTestsparingly.
Common Pitfalls & How to Avoid Them
- Bean Ambiguity: Provide
@Qualifieror@Primarywhen multiple beans of the same type exist. - Lazy CORS Config: Don’t use
@CrossOrigin("*")in production; prefer restricted origins and a global CORS config. - Transaction Misuse:
@Transactionalon read-only queries improves performance (hint to Hibernate). - Validation Gaps: Put
@Validon nested DTOs too; ensure validation dependencies are included. - Profile Leakage: Ensure
spring.profiles.activeis set correctly in each environment. - Scheduling Time Zones: Cron defaults to server time; set
zone = "Asia/Kolkata"(or your region) explicitly if needed.
Handy Cheat Sheet (What to Reach For)
- Bootstrapping →
@SpringBootApplication - Beans & Config →
@Configuration,@Bean,@ConfigurationProperties - DI & Components →
@Service,@Repository,@RestController,@Autowired,@Qualifier - Web MVC →
@GetMapping,@PostMapping,@PathVariable,@RequestParam,@RequestBody,@ControllerAdvice - Validation →
@Valid,@NotNull,@Size,@Email - Persistence →
@Entity,@Id,@GeneratedValue,@Transactional - Caching →
@EnableCaching,@Cacheable,@CacheEvict,@CachePut - Async & Scheduling →
@EnableAsync,@Async,@EnableScheduling,@Scheduled - Security →
@EnableWebSecurity,@EnableMethodSecurity,@PreAuthorize - Testing →
@SpringBootTest,@WebMvcTest,@DataJpaTest,@MockBean



Post Comment