Spring Core
The foundation of the Spring ecosystem — Inversion of Control (IoC) and Dependency Injection (DI).
Spring's IoC container manages the lifecycle and wiring of application components (beans).
- IoC Container:
ApplicationContextcreates, configures, and manages beans based on metadata (annotations or XML). - Constructor Injection (preferred): Dependencies provided via constructor — immutable, testable, and makes required dependencies explicit.
- Setter Injection: For optional dependencies. Less preferred as it allows partially constructed objects.
- Field Injection (
@Autowired): Convenient but hides dependencies. Avoid in production code — hard to test without Spring context.
Bean Scopes
- Singleton (default): One instance per container. Shared across all injection points.
- Prototype: New instance per injection. Use for stateful beans.
- Request: One instance per HTTP request (web apps only).
- Session: One instance per HTTP session.
- Instantiation: Container creates the bean (via constructor, factory method, or reflection).
- Dependency Injection: Container injects dependencies (constructor, setter, or field).
- Aware Interfaces:
BeanNameAware,ApplicationContextAware— bean receives metadata about itself. - Post-Processing:
BeanPostProcessor.postProcessBeforeInitialization()— run before init. - Initialisation:
@PostConstructmethod orInitializingBean.afterPropertiesSet(). - Post-Processing:
BeanPostProcessor.postProcessAfterInitialization()— run after init (proxies created here). - Ready for Use: Bean is fully initialised and available.
- Destruction:
@PreDestroymethod orDisposableBean.destroy()— cleanup resources.
Cross-cutting concerns (logging, security, transactions) separated from business logic using aspects.
- Aspect: A module encapsulating a cross-cutting concern (e.g.,
@Aspectclass for logging). - Join Point: A point in execution where an aspect can be applied (method execution in Spring AOP).
- Pointcut: Expression that selects join points —
@Pointcut("execution(* com.example.service.*.*(..))"). - Advice Types:
@Before— Run before the method.@After— Run after (regardless of outcome).@AfterReturning— Run after successful return.@AfterThrowing— Run after exception.@Around— Wraps the method — most powerful, controls whether to proceed.
- Proxy-Based: Spring AOP uses JDK dynamic proxies (interfaces) or CGLIB proxies (classes). Self-invocation within a bean bypasses AOP — a common pitfall.
Spring Boot
Opinionated, production-ready Spring applications with minimal configuration.
- Auto-Configuration: Spring Boot automatically configures beans based on classpath dependencies. E.g., add
spring-boot-starter-data-jpa→ auto-configuresDataSource,EntityManagerFactory,TransactionManager. - Starters: Curated dependency sets —
spring-boot-starter-web,spring-boot-starter-security,spring-boot-starter-test. One dependency brings everything you need. - Conditional Beans:
@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnProperty— auto-config activates only when conditions are met. - Overriding Defaults: Define your own bean to override auto-configured one. Or use
application.properties/application.ymlfor property-based configuration.
- application.properties / application.yml: Externalised configuration — database URLs, server ports, feature flags.
- Profiles: Activate environment-specific config with
spring.profiles.active=dev. Useapplication-dev.yml,application-prod.ymlfor environment-specific overrides. - @ConfigurationProperties: Type-safe binding of properties to POJOs — validated with
@Validated, immutable with@ConstructorBinding. - Property Sources Priority: Command line args → environment variables → application-{profile}.yml → application.yml → defaults.
- Secrets Management: Never commit secrets. Use environment variables, Spring Cloud Config with Vault, or AWS Secrets Manager.
- Health Checks:
/actuator/health— readiness and liveness probes for Kubernetes. Custom health indicators for database, external services. - Metrics:
/actuator/metrics— JVM, HTTP request, and custom metrics via Micrometer. Export to Prometheus, Datadog, CloudWatch. - Info:
/actuator/info— build info, git info, custom properties. - Environment:
/actuator/env— view resolved configuration properties (secured in production). - Security: Expose only health and info endpoints publicly. Secure all others behind authentication.
Spring MVC
Building web applications and REST APIs with Spring's Model-View-Controller framework.
- @RestController: Combines
@Controller+@ResponseBody— every method returns data (JSON/XML), not a view. - Request Mapping:
@GetMapping,@PostMapping,@PutMapping,@DeleteMapping,@PatchMapping. - Path Variables:
@PathVariable—/users/{id}→getUserById(@PathVariable Long id). - Request Body:
@RequestBody— deserialise JSON to Java object.@Validfor Bean Validation. - Query Parameters:
@RequestParam—/search?q=spring→search(@RequestParam String q). - Response:
ResponseEntity<T>for full control over status code, headers, and body.
- @ControllerAdvice: Global exception handler for all controllers — centralised error handling.
- @ExceptionHandler: Handle specific exception types — return consistent error response DTOs.
- Problem Details (RFC 7807): Standard error response format —
type,title,status,detail,instance. Spring Boot 3+ supports this natively. - Custom Exceptions: Domain-specific exceptions (e.g.,
ResourceNotFoundException) mapped to appropriate HTTP status codes.
- Bean Validation:
@NotNull,@Size,@Email,@Min,@Max,@Pattern— on request body fields. - Custom Validators: Implement
ConstraintValidator<A, T>for business-specific validation rules. - Content Negotiation: Spring MVC negotiates response format based on
Acceptheader — JSON (default via Jackson), XML (add jackson-dataformat-xml). - Message Converters:
HttpMessageConverterhandles serialisation/deserialisation. Jackson'sObjectMapperconfigured automatically.
Spring Data
Simplified data access with repository abstractions for relational and NoSQL databases.
- JpaRepository: Interface-based repositories — CRUD + pagination + sorting out of the box. No implementation needed.
- Query Methods: Derive queries from method names —
findByEmailAndStatus(String email, Status status). - @Query: Custom JPQL or native SQL —
@Query("SELECT u FROM User u WHERE u.active = true"). - Projections: Return partial data — interface projections (select specific fields), DTO projections (constructor expressions).
- Pagination:
Page<T>+Pageableparameter — clients control page size and sort order. - Specifications: Dynamic query building for complex search/filter scenarios — type-safe criteria queries.
- @Entity / @Table: Map Java class to database table.
@Id+@GeneratedValuefor primary key. - Relationships:
@OneToMany/@ManyToOne— parent-child relationships (e.g., Order → OrderItems).@ManyToMany— junction table for many-to-many (e.g., Student ↔ Course).@OneToOne— shared primary key or foreign key.
- Fetch Types:
LAZY(default for collections) loads on access.EAGERloads immediately. Prefer LAZY + explicit fetch joins to avoid N+1 queries. - N+1 Problem: Loading 100 orders then 100 separate queries for items. Solution:
@EntityGraph,JOIN FETCHin JPQL, or@BatchSize.
- @Transactional: Declarative transaction management — method executes within a database transaction. Rollback on unchecked exceptions by default.
- Propagation:
REQUIRED(default) — join existing or create new.REQUIRES_NEW— always create new (suspends existing).MANDATORY— must run within existing transaction.NESTED— savepoint within existing transaction.
- Isolation Levels:
READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE— trade consistency for performance. - Read-Only:
@Transactional(readOnly = true)— optimises reads (no dirty checking, may route to read replica). - Proxy Pitfall:
@Transactionalworks via proxy — self-invocation within the same class bypasses the proxy. Solution: extract into a separate bean.
Spring Security
Comprehensive authentication and authorisation framework for Java applications.
- SecurityFilterChain: Spring Security's servlet filter chain — intercepts every request and applies security rules.
- Authentication: Verify identity — form login, HTTP Basic, JWT, OAuth2/OIDC.
- Authorisation: Verify permissions — URL-based (
.requestMatchers("/admin/**").hasRole("ADMIN")) and method-based (@PreAuthorize). - UserDetailsService: Interface to load user data — implement to connect Spring Security to your user store (database, LDAP).
- PasswordEncoder:
BCryptPasswordEncoder— industry standard. Never store plain text passwords.
JWT (JSON Web Tokens)
- Stateless authentication — token contains claims (user ID, roles, expiry). No server-side session needed.
- Flow: Client authenticates → server issues signed JWT → client sends JWT in
Authorization: Bearerheader → server validates signature and claims. - Implementation: Custom
OncePerRequestFilterto extract, validate, and setSecurityContext.
OAuth2 / OpenID Connect
- OAuth2 Client:
spring-boot-starter-oauth2-client— "Login with Google/GitHub". Handles redirect flows automatically. - Resource Server:
spring-boot-starter-oauth2-resource-server— validates JWTs issued by an authorization server (Keycloak, Auth0, Okta). - OIDC: Extension of OAuth2 that adds identity tokens — standard claims for user profile (name, email).
- CORS: Configure allowed origins, methods, and headers in
SecurityFilterChain. Never useallowedOrigins("*")in production. - CSRF: Enabled by default for session-based apps. Disable for stateless REST APIs (
csrf(csrf -> csrf.disable())). - Security Headers: Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security — Spring Security adds these by default.
- Rate Limiting: Not built into Spring Security — use API Gateway (Kong, AWS API Gateway) or a filter with Bucket4j/Resilience4j.
Spring Cloud
Tools for building distributed systems — service discovery, configuration, resilience, and gateway.
- Eureka: Netflix service registry — services register themselves, clients discover via registry lookup. Health checks ensure only healthy instances are returned.
- Spring Cloud Config: Centralised configuration server — stores config in Git, Vault, or filesystem. Clients fetch config at startup and can refresh dynamically.
- Consul: Alternative to Eureka — service discovery + key/value config + health checking in one tool.
- Kubernetes-Native: In K8s, use native service discovery (DNS) and ConfigMaps/Secrets instead of Eureka/Config Server.
- Resilience4j: Lightweight fault-tolerance library — replaces Netflix Hystrix.
- Circuit Breaker: Closed → Open (on failure threshold) → Half-Open (test recovery). Prevents cascading failures.
- Retry: Automatic retries with exponential backoff —
@Retry(name = "service", fallbackMethod = "fallback"). - Rate Limiter: Limit call rate to a downstream service — prevents overwhelming a recovering service.
- Bulkhead: Isolate service calls into separate thread pools — failure in one call path doesn't exhaust threads for others.
- Time Limiter: Timeout for async operations — fail fast rather than waiting indefinitely.
- API Gateway built on Spring WebFlux — reactive, non-blocking.
- Route Configuration: Match requests by path, header, method, or query parameter → route to downstream services.
- Filters: Pre/post filters for logging, authentication, rate limiting, request/response modification.
- Load Balancing: Integrates with service discovery (Eureka) for client-side load balancing via
lb://URIs. - Predicates:
Path,Method,Header,Cookie,After/Before(time-based) — flexible routing rules.
Integration Patterns
Connecting Spring applications with messaging systems, external services, and batch processing.
- KafkaTemplate: Send messages to Kafka topics —
kafkaTemplate.send("topic", key, value). - @KafkaListener: Consume messages from topics —
@KafkaListener(topics = "orders", groupId = "order-service"). - Consumer Groups: Multiple consumers in a group share partitions — horizontal scaling of consumption.
- Serialisation: JSON serialiser/deserialiser for complex objects. Configure in
application.yml. - Error Handling: Dead-letter topic for failed messages. Retry with backoff before sending to DLT.
- Exactly-Once: Transactional producers + idempotent consumers for exactly-once semantics in critical flows.
- Framework for batch processing — large-volume data operations (ETL, report generation, data migration).
- Job → Step → (Reader → Processor → Writer): Chunk-oriented processing pipeline.
- ItemReader: Read from database, file, or API —
JdbcCursorItemReader,FlatFileItemReader. - ItemProcessor: Transform or filter items — business logic applied per item.
- ItemWriter: Write to database, file, or API —
JdbcBatchItemWriter,FlatFileItemWriter. - Job Repository: Tracks job execution state — restart failed jobs from last successful checkpoint.
- Scheduling: Trigger jobs via
@Scheduled, Quartz, or external scheduler (cron, Airflow).
- RestClient (Spring 6.1+): Fluent, synchronous HTTP client — replaces
RestTemplate. Clean API for GET/POST/PUT/DELETE operations. - WebClient: Non-blocking, reactive HTTP client from Spring WebFlux —
WebClient.create().get().uri("/api/users").retrieve().bodyToFlux(User.class). - Declarative Clients (Spring 6.0+): Define HTTP interfaces with
@HttpExchangeannotations — similar to Feign but built into Spring. - Timeouts: Always configure connection and read timeouts. Don't rely on defaults — they're often too long or infinite.
- Retries: Combine with Resilience4j for retry + circuit breaker on external API calls.
Spring Boot Tutorial
Step-by-step guide to building a production-ready REST API with Spring Boot.
- Spring Initializr:
start.spring.io— select dependencies (Web, JPA, Security, Actuator), generate project skeleton. - Project Structure:
src/main/java/com/example/ ├── config/ # Configuration classes ├── controller/ # REST controllers ├── service/ # Business logic ├── repository/ # Data access (JPA repositories) ├── model/ # Entity classes ├── dto/ # Data transfer objects ├── exception/ # Custom exceptions + handler └── Application.java # Main class - Dependencies: Use starters —
spring-boot-starter-web,spring-boot-starter-data-jpa,spring-boot-starter-validation. - Dev Tools:
spring-boot-devtoolsfor auto-restart on code changes during development.
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public Page<UserDTO> getUsers(Pageable pageable) {
return userService.findAll(pageable);
}
@GetMapping("/{id}")
public UserDTO getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDTO createUser(@Valid @RequestBody CreateUserRequest request) {
return userService.create(request);
}
@PutMapping("/{id}")
public UserDTO updateUser(@PathVariable Long id, @Valid @RequestBody UpdateUserRequest request) {
return userService.update(id, request);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
} Key practices: constructor injection, DTOs for input/output, validation with @Valid, proper HTTP status codes, pagination out of the box.
- Unit Tests: Test services and business logic in isolation with Mockito —
@ExtendWith(MockitoExtension.class). - Integration Tests: Test the full stack —
@SpringBootTestwithTestRestTemplateorMockMvc. - Repository Tests:
@DataJpaTest— auto-configures in-memory database, scans only JPA components. - Web Layer Tests:
@WebMvcTest(UserController.class)— test controllers without loading the full context. - Testcontainers: Real databases in Docker for integration tests —
@Testcontainers+@DynamicPropertySource.
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired private MockMvc mockMvc;
@MockBean private UserService userService;
@Test
void shouldReturnUser() throws Exception {
when(userService.findById(1L))
.thenReturn(new UserDTO(1L, "Vinay", "vinay@example.com"));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Vinay"));
}
}