Java Spring Boot Basics Cheat Sheet
Covers the application entry point, REST controllers, service and repository layers, core annotations, and application.properties configuration.
Application Entry Point
The bootstrap class that starts a Spring Boot application.
@SpringBootApplication // combines @Configuration, @EnableAutoConfiguration, @ComponentScanpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}
REST Controller
Map HTTP requests to Java methods and return JSON responses.
@RestController@RequestMapping("/api/users")public class UserController { private final UserService userService; // constructor injection (preferred) public UserController(UserService userService) { this.userService = userService; } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return userService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping public ResponseEntity<User> create(@RequestBody @Valid User user) { User saved = userService.save(user); return ResponseEntity.status(HttpStatus.CREATED).body(saved); }}
Service & Repository Layers
Separate business logic from data access using Spring Data JPA.
@Servicepublic class UserService { private final UserRepository repo; public UserService(UserRepository repo) { this.repo = repo; } public Optional<User> findById(Long id) { return repo.findById(id); } public User save(User user) { return repo.save(user); }}@Repositorypublic interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); // Spring Data derives the query from the method name}
Core Spring Boot Annotations
The annotations you'll see in nearly every Spring Boot project.
- @SpringBootApplication- Bootstraps the app; enables component scanning and auto-configuration
- @RestController- @Controller + @ResponseBody; return values are serialized directly to the response body (usually JSON)
- @Service- Marks a class as a business-logic bean, picked up by component scanning
- @Repository- Marks a data-access bean; also translates persistence exceptions into Spring's DataAccessException hierarchy
- @Component- Generic stereotype for any Spring-managed bean
- @Autowired- Injects a dependency; constructor injection (no annotation needed on the constructor itself) is the recommended style
- @Value- Injects a property value from application.properties/.yml: @Value("${server.port}")
- @Configuration / @Bean- Defines Java-based configuration classes and manually registered beans
application.properties Configuration
Externalize datasource, port, and JPA settings, with profile support.
# application.propertiesserver.port=8081spring.datasource.url=jdbc:postgresql://localhost:5432/appdbspring.datasource.username=postgresspring.datasource.password=secretspring.jpa.hibernate.ddl-auto=updatespring.jpa.show-sql=true# Environment-specific: application-prod.properties, activated with# spring.profiles.active=prod
Global Exception Handling
Centralize error responses with @RestControllerAdvice instead of try/catch in every controller.
@RestControllerAdvicepublic class ApiExceptionHandler { @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) { ErrorResponse body = new ErrorResponse("NOT_FOUND", ex.getMessage()); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors() .forEach(err -> errors.put(err.getField(), err.getDefaultMessage())); return ResponseEntity.badRequest().body(errors); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) { return ResponseEntity.internalServerError() .body(new ErrorResponse("INTERNAL_ERROR", "Unexpected error")); }}
Securing Endpoints with Spring Security
Define a stateless SecurityFilterChain bean for JWT-based REST APIs.
@Configuration@EnableWebSecuritypublic class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(csrf -> csrf.disable()) .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**", "/actuator/health").permitAll() .requestMatchers(HttpMethod.GET, "/api/public/**").permitAll() .anyRequest().authenticated()) .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class) .build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}
Type-Safe Config with @ConfigurationProperties
Bind grouped configuration into a validated, immutable POJO instead of scattering @Value fields.
@ConfigurationProperties(prefix = "app.mail")@Validatedpublic record MailProperties( @NotBlank String host, @Min(1) @Max(65535) int port, boolean tlsEnabled) {}// Enable it explicitly (or rely on component scan with @Component)@Configuration@EnableConfigurationProperties(MailProperties.class)class MailConfig {}// application-prod.properties overrides application.properties when// spring.profiles.active=prod, following Spring's property precedence order.
Async Methods & Application Events
Decouple side effects from the request thread using @Async and ApplicationEventPublisher.
@EnableAsync@Configurationclass AsyncConfig {}@Serviceclass UserService { private final ApplicationEventPublisher publisher; User save(User user) { User saved = repo.save(user); publisher.publishEvent(new UserCreatedEvent(saved.getId())); return saved; }}@Componentclass WelcomeEmailListener { @Async @EventListener void onUserCreated(UserCreatedEvent event) { // runs on a separate thread pool, after the transaction that // published it (use @TransactionalEventListener to wait for commit) }}
Actuator, Testing & Transactions
Production-readiness and testing concepts beyond the basic CRUD layer.
- spring-boot-starter-actuator- Exposes /actuator/health, /metrics, /info endpoints for monitoring; lock down non-health endpoints in production
- @Transactional- Wraps a service method in a DB transaction; rolls back on unchecked exceptions by default, not checked ones
- @SpringBootTest- Boots the full ApplicationContext for integration tests; slower than slice tests
- @WebMvcTest / @DataJpaTest- Slice tests that load only the web layer or JPA layer, keeping tests fast
- TestRestTemplate / MockMvc- Drive HTTP calls in tests, either against a real embedded server or a mocked dispatcher
- @ControllerAdvice order- Multiple advices can be ordered with @Order; the most specific @ExceptionHandler match wins regardless of advice order
- Bean scopes- Default is singleton; use @Scope("prototype") for a new instance per injection point
Prefer constructor injection over field injection (@Autowired on a field) - it makes dependencies explicit, allows fields to be final, and makes the class trivially testable without needing a Spring context to instantiate mocks.