Spring Boot & API Interview Preparation
Table of Contents
Section titled “Table of Contents”- Optimizing a Spring Boot Application
- IoC — Inversion of Control
- Dependency Injection
- Spring Bean Lifecycle
- Singleton vs Prototype
- Securing REST APIs
- Troubleshooting a Slow API
- REST vs GraphQL vs gRPC
- Senior/Lead Interview Summary
1. Optimizing a Spring Boot Application
Section titled “1. Optimizing a Spring Boot Application”Interview Question
Section titled “Interview Question”How would you optimize a Spring Boot application handling millions of requests daily?
I would optimize the application across the complete request path rather than focusing only on Spring Boot code.
The first step is to identify the actual bottleneck using metrics, logs, tracing, and profiling.
1.1 Identify the Bottleneck
Section titled “1.1 Identify the Bottleneck”Monitor:
- API latency — P50/P95/P99
- Requests per second
- CPU and memory utilization
- GC pauses
- Thread-pool utilization
- Database connection-pool usage
- Database query latency
- Cache hit/miss ratio
- External API latency
- Error and timeout rate
Typical observability stack:
Spring Boot | +--> Spring Boot Actuator | +--> Micrometer | +--> Prometheus | +--> Grafana | +--> OpenTelemetry / Distributed Tracing1.2 Optimize the Application Layer
Section titled “1.2 Optimize the Application Layer”Avoid unnecessary processing.
Keep controllers thin:
@GetMapping("/customers/{id}")public CustomerDto getCustomer(@PathVariable Long id) { return customerService.getCustomer(id);}Use:
- Efficient algorithms
- Pagination
- DTOs
- Lazy loading where appropriate
- Projections
- Minimal object creation
- Appropriate data structures
Do not load 100,000 records when the UI needs only 20.
Page<CustomerDto> findCustomers(Pageable pageable);1.3 Database Optimization
Section titled “1.3 Database Optimization”Database performance is often a major bottleneck.
I would:
- Add appropriate indexes
- Analyze slow queries
- Eliminate N+1 queries
- Use projections for read-heavy APIs
- Use pagination
- Optimize joins
- Tune connection pooling
- Consider read replicas
- Consider partitioning/sharding for very large datasets
Example Hikari configuration:
spring.datasource.hikari.maximum-pool-size=30spring.datasource.hikari.minimum-idle=10spring.datasource.hikari.connection-timeout=3000The pool size should be determined through load testing rather than simply increasing it.
1.4 Caching
Section titled “1.4 Caching”Use caching for frequently accessed, relatively stable data.
Typical choices include Redis.
flowchart LR
Client --> API[Spring Boot API]
API --> Cache[Redis Cache]
Cache -->|Cache Miss| DB[(Database)]
DB --> Cache
Cache --> API
API --> Client
Example:
@Cacheable(value = "products", key = "#id")public Product getProduct(Long id) { return repository.findById(id).orElseThrow();}Consider:
- TTL
- Cache invalidation
- Cache size
- Cache stampede protection
- Cache consistency
1.5 Stateless Services
Section titled “1.5 Stateless Services”For horizontal scaling, keep services stateless where practical.
flowchart TD
Client --> LB[Load Balancer]
LB --> A1[Spring Boot Instance 1]
LB --> A2[Spring Boot Instance 2]
LB --> A3[Spring Boot Instance 3]
A1 --> Redis[(Redis)]
A2 --> Redis
A3 --> Redis
A1 --> DB[(Database)]
A2 --> DB
A3 --> DB
This allows instances to be added or removed without requiring sticky sessions.
1.6 Thread Pool Optimization
Section titled “1.6 Thread Pool Optimization”Tune:
- Tomcat/Jetty thread pool
- Async executor
- Database connection pool
- HTTP client connection pool
- Kafka consumer configuration
Do not simply increase the number of threads.
Too many threads can cause:
More Threads ↓Context Switching ↓CPU Contention ↓Higher Latency ↓Lower ThroughputFor I/O-heavy workloads, evaluate Java Virtual Threads when the application and dependencies are suitable.
1.7 Downstream Services
Section titled “1.7 Downstream Services”For external or downstream service calls, use:
- Timeouts
- Retry with exponential backoff
- Circuit breakers
- Bulkheads
- Rate limiting
- Fallbacks where appropriate
Example flow:
flowchart LR
Request --> Timeout
Timeout --> Retry
Retry --> CB[Circuit Breaker]
CB --> Downstream[Downstream Service]
CB --> Fallback[Fallback]
Retries should be used carefully, especially for non-idempotent operations.
1.8 Asynchronous Processing
Section titled “1.8 Asynchronous Processing”Move non-critical work out of the synchronous request path.
Example:
flowchart LR
Client --> API[POST /order]
API --> Order[Create Order]
Order --> Kafka[Kafka Event]
Order --> Response[Return Response]
Kafka --> Email[Email Consumer]
Kafka --> Inventory[Inventory Consumer]
Kafka --> Analytics[Analytics Consumer]
This prevents slow downstream processing from blocking the API request.
1.9 JVM and Garbage Collection
Section titled “1.9 JVM and Garbage Collection”Monitor:
- Heap utilization
- Allocation rate
- Old-generation usage
- GC pause time
- Memory leaks
Evaluate G1GC or, depending on latency requirements and Java version, ZGC.
Do not simply increase -Xmx without understanding the memory behavior.
1.10 Horizontal Scaling
Section titled “1.10 Horizontal Scaling”For millions of requests, make the application horizontally scalable.
With Kubernetes:
- Horizontal Pod Autoscaler
- CPU/memory metrics
- Custom metrics such as request rate
- Readiness/liveness probes
- Rolling deployments
1.11 API Gateway
Section titled “1.11 API Gateway”For microservices:
flowchart LR
Client --> Gateway[API Gateway]
Gateway --> User[User Service]
Gateway --> Order[Order Service]
Gateway --> Payment[Payment Service]
The gateway can handle:
- Authentication
- Routing
- Rate limiting
- Correlation IDs
- TLS termination
- API versioning
1.12 Observability
Section titled “1.12 Observability”Every request should have a correlation or trace ID.
sequenceDiagram
participant C as Client
participant G as API Gateway
participant O as Order Service
participant P as Payment Service
participant D as Database
C->>G: Request traceId=abc123
G->>O: Request traceId=abc123
O->>P: Payment request
P->>D: Query
D-->>P: Result
P-->>O: Payment result
O-->>G: Response
G-->>C: Response
Collect:
Metrics
Section titled “Metrics”- Throughput
- Latency
- Errors
- CPU/memory
- DB pool utilization
- Request/correlation ID
- Endpoint
- HTTP status
- Error details
- Business identifiers where appropriate
Traces
Section titled “Traces”- Service-to-service latency
- Database latency
- External API latency
1.13 Load Testing
Section titled “1.13 Load Testing”Test:
Normal Load ↓Peak Load ↓Stress Test ↓Failure Scenarios ↓RecoveryUse realistic traffic patterns and validate every performance change.
Interview Answer
Section titled “Interview Answer”For a Spring Boot application handling millions of requests daily, I would first identify the bottleneck using metrics, logs and distributed tracing rather than optimizing blindly. At the application level I would optimize expensive operations, use pagination and DTOs, and tune thread pools. At the database level I would optimize queries and indexes, eliminate N+1 problems, use connection pooling and potentially read replicas. For frequently accessed data I would introduce Redis caching with proper TTL and invalidation. I would keep services stateless so they can scale horizontally behind a load balancer or Kubernetes HPA. For downstream services I would use timeouts, retries, circuit breakers and bulkheads, while Kafka can be used for asynchronous processing. Finally, I would validate the architecture with load testing and continuously monitor P95/P99 latency, throughput, errors, JVM/GC, database and cache metrics.
Lead-level phrase:
I optimize based on measured bottlenecks and validate every change through load testing and production observability.
2. IoC — Inversion of Control
Section titled “2. IoC — Inversion of Control”Normally, a Java class creates and manages its own dependencies:
class OrderService {
private PaymentService paymentService = new PaymentService();}Here, OrderService controls the creation of PaymentService.
With IoC, Spring takes control of object creation and dependency management.
@Serviceclass OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) { this.paymentService = paymentService; }}Spring creates the objects and manages their relationships.
flowchart LR
App[Application Code] --> Container[Spring IoC Container]
Container --> Order[OrderService Bean]
Container --> Payment[PaymentService Bean]
Order --> Payment
Interview One-Liner
Section titled “Interview One-Liner”IoC means the control of creating and managing objects is transferred from the application code to the Spring IoC container.
Common container interfaces:
BeanFactoryApplicationContext
Spring Boot applications commonly use ApplicationContext.
3. Dependency Injection
Section titled “3. Dependency Injection”Dependency Injection is the mechanism Spring uses to implement IoC.
Suppose:
class OrderService { private PaymentService paymentService;}OrderService depends on PaymentService.
Instead of creating it:
PaymentService paymentService = new PaymentService();Spring injects it.
3.1 Constructor Injection
Section titled “3.1 Constructor Injection”Preferred approach:
@Servicepublic class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) { this.paymentService = paymentService; }}Benefits:
- Dependencies are explicit
- Supports immutable fields
- Easier unit testing
- Prevents partially initialized objects
- Makes mandatory dependencies clear
3.2 Setter Injection
Section titled “3.2 Setter Injection”@Autowiredpublic void setPaymentService(PaymentService paymentService) { this.paymentService = paymentService;}Useful when a dependency is optional or needs to be changed after construction.
3.3 Field Injection
Section titled “3.3 Field Injection”@Autowiredprivate PaymentService paymentService;Generally avoided because:
- Dependencies are hidden
- Harder to unit test
- Prevents straightforward immutability
- Encourages partially initialized objects
Interview One-Liner
Section titled “Interview One-Liner”Dependency Injection means an object’s dependencies are provided by an external container rather than the object creating those dependencies itself.
4. Spring Bean Lifecycle
Section titled “4. Spring Bean Lifecycle”A simplified Spring bean lifecycle:
flowchart TD
A[Application Starts] --> B[Bean Definition]
B --> C[Bean Instantiation]
C --> D[Dependency Injection]
D --> E[Aware Callbacks]
E --> F[BeanPostProcessor Before Initialization]
F --> G["@PostConstruct"]
G --> H["afterPropertiesSet()"]
H --> I[Custom Init Method]
I --> J[BeanPostProcessor After Initialization]
J --> K[Bean Ready]
K --> L[Application Uses Bean]
L --> M[Application Shutdown]
M --> N["@PreDestroy"]
N --> O["DisposableBean.destroy()"]
O --> P[Bean Destroyed]
Example:
@Componentpublic class PaymentService {
public PaymentService() { System.out.println("Constructor"); }
@PostConstruct public void init() { System.out.println("PostConstruct"); }
@PreDestroy public void destroy() { System.out.println("PreDestroy"); }}Typical sequence:
Constructor ↓Dependency Injection ↓@PostConstruct ↓Bean Available ↓@PreDestroyImportant Points
Section titled “Important Points”@PostConstruct is useful for initialization after dependencies have been injected.
@PreDestroy is useful for cleanup.
5. Singleton vs Prototype
Section titled “5. Singleton vs Prototype”These are Spring bean scopes.
5.1 Singleton
Section titled “5.1 Singleton”Singleton is the default Spring bean scope.
@Servicepublic class OrderService {}Spring creates one bean instance per Spring IoC container.
flowchart TD
C[Spring ApplicationContext] --> O[OrderService Singleton]
A[OrderController] --> O
B[OrderProcessor] --> O
Important Clarification
Section titled “Important Clarification”Spring Singleton does not mean one instance for the entire JVM.
It means:
One instance per Spring ApplicationContext/container.
Singleton beans are normally shared, so avoid mutable request-specific state inside them.
5.2 Prototype
Section titled “5.2 Prototype”@Component@Scope("prototype")public class ReportGenerator {}Spring creates a new instance whenever the bean is requested from the container.
flowchart TD
C[Spring Container] --> R1[ReportGenerator #1]
C --> R2[ReportGenerator #2]
C --> R3[ReportGenerator #3]
Singleton vs Prototype
Section titled “Singleton vs Prototype”| Feature | Singleton | Prototype |
|---|---|---|
| Default? | Yes | No |
| Instances | One per container | New instance when requested |
| Shared? | Yes | No |
| Suitable for | Stateless services | Stateful/short-lived objects |
| Memory usage | Lower | Higher |
| Destruction | Spring manages lifecycle | Spring does not fully manage destruction |
5.3 Prototype Injected into Singleton
Section titled “5.3 Prototype Injected into Singleton”This is a common senior interview question.
@Servicepublic class OrderService {
private final ReportGenerator reportGenerator;
public OrderService(ReportGenerator reportGenerator) { this.reportGenerator = reportGenerator; }}Where:
@Scope("prototype")@Componentclass ReportGenerator {}Even though ReportGenerator is prototype scoped, normal injection into a singleton means one prototype instance is created when the singleton is created and remains referenced by the singleton.
It does not automatically create a new prototype instance every time OrderService is used.
For a fresh prototype instance, use ObjectProvider:
@Servicepublic class OrderService {
private final ObjectProvider<ReportGenerator> provider;
public OrderService(ObjectProvider<ReportGenerator> provider) { this.provider = provider; }
public void process() { ReportGenerator generator = provider.getObject(); }}Key Interview Statements
Section titled “Key Interview Statements”IoC: Spring takes control of object creation and lifecycle.
Dependency Injection: Spring provides the dependencies required by an object.
Bean Lifecycle: Spring creates, injects, initializes, manages and destroys beans where applicable.
Singleton vs Prototype: Singleton provides one instance per Spring container, while Prototype provides a new instance whenever the bean is requested.
6. Securing REST APIs
Section titled “6. Securing REST APIs”Interview Question
Section titled “Interview Question”How do you secure REST APIs? Discuss JWT, OAuth2, Refresh Tokens, and Session Management.
A strong approach is to use OAuth2/OIDC with an established identity provider, short-lived access tokens, secure refresh-token handling, Spring Security authorization, and defense-in-depth.
flowchart LR
U[User] --> C[React / Mobile Client]
C --> AS[Authorization Server]
AS --> AT[Access Token]
AS --> RT[Refresh Token]
AT --> API[Spring Boot API]
API --> V[Spring Security JWT Validation]
V --> AUTH[Authorization]
AUTH --> RES[Protected Resource]
6.1 JWT
Section titled “6.1 JWT”JWT stands for JSON Web Token.
A JWT is commonly used as an access token.
Typical flow:
User | | Login vAuthorization Server | | Access Token vClient | | Authorization: Bearer <JWT> vSpring Boot API | | Validate JWT vAllow / RejectExample claims:
{ "sub": "12345", "iss": "https://auth.example.com", "aud": "order-api", "scope": "orders:read orders:write", "exp": 1780000000}Validate:
- Signature
- Issuer
- Audience
- Expiration
- Not-before when applicable
- Required scopes/roles
Important
Section titled “Important”JWT is signed by default, not encrypted.
Do not put passwords or sensitive confidential data into the payload.
6.2 Spring Security Resource Server
Section titled “6.2 Spring Security Resource Server”Example:
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .requestMatchers("/orders/**") .hasAuthority("SCOPE_orders:read") .anyRequest().authenticated() ) .oauth2ResourceServer(oauth -> oauth.jwt());
return http.build(); }}6.3 OAuth2
Section titled “6.3 OAuth2”OAuth2 is primarily an authorization framework.
For user authentication and identity, OAuth2 is commonly combined with OpenID Connect (OIDC).
OAuth2 Roles
Section titled “OAuth2 Roles”| Component | Responsibility |
|---|---|
| Resource Owner | User |
| Client | React/mobile application |
| Authorization Server | Authenticates user and issues tokens |
| Resource Server | Spring Boot API |
| Access Token | Grants access to resources |
For enterprise systems, use an established identity provider rather than implementing authentication from scratch.
6.4 Refresh Tokens
Section titled “6.4 Refresh Tokens”Access tokens should generally be short-lived.
sequenceDiagram
participant C as Client
participant AS as Authorization Server
participant API as Spring Boot API
C->>AS: Login
AS-->>C: Access Token + Refresh Token
C->>API: Bearer Access Token
API-->>C: API Response
C->>AS: Refresh Token
AS-->>C: New Access Token
Refresh tokens allow the client to obtain new access tokens without requiring the user to log in repeatedly.
Refresh Token Security
Section titled “Refresh Token Security”Consider:
- Controlled refresh-token lifetime
- Secure storage
- Refresh-token rotation
- Reuse detection
- Revocation
- HTTPS
- Avoid exposing refresh tokens to JavaScript where possible
For browser applications, a common design is to keep refresh credentials in a Secure, HttpOnly, appropriately scoped cookie.
6.5 Session Management
Section titled “6.5 Session Management”JWT-based APIs can be stateless.
Request ↓Bearer JWT ↓Validate Token ↓AuthorizeThis supports horizontal scaling:
flowchart TD
LB[Load Balancer] --> A1[API Instance 1]
LB --> A2[API Instance 2]
LB --> A3[API Instance 3]
However, stateless APIs can still have centralized state for:
- Refresh tokens
- Revocation
- User/device sessions
- Token rotation
For example:
flowchart LR
A1[API 1] --> R[Redis / Session Store]
A2[API 2] --> R
A3[API 3] --> R
6.6 Authentication vs Authorization
Section titled “6.6 Authentication vs Authorization”Authentication:
Who are you?
Authorization:
What are you allowed to do?
Example:
@PreAuthorize("hasRole('ADMIN')")public void deleteUser(Long id) {}Or scope-based authorization:
.requestMatchers("/orders/**").hasAuthority("SCOPE_orders:read")Also enforce resource-level authorization.
A valid JWT does not automatically mean the user can access every resource.
User A | +--> Order 100: Allowed | +--> Order 200: Forbidden6.7 Additional REST Security
Section titled “6.7 Additional REST Security”JWT/OAuth2 alone is not enough.
Always use TLS.
Input Validation
Section titled “Input Validation”@NotBlank@Size(max = 100)@EmailRate Limiting
Section titled “Rate Limiting”Protect sensitive endpoints from abuse.
Configure allowed origins explicitly.
Avoid unrestricted origins for security-sensitive authenticated applications.
CSRF requirements depend on the authentication mechanism.
Cookie-based authentication requires careful CSRF protection because browsers automatically attach cookies.
Bearer-token APIs that use an Authorization header have a different CSRF risk model.
Secure Logging
Section titled “Secure Logging”Never log:
- Passwords
- Authorization headers
- Access tokens
- Refresh tokens
- Secrets
Log safe metadata such as:
userIdclientIdendpointHTTP statustimestamptraceId7. Troubleshooting a Slow API
Section titled “7. Troubleshooting a Slow API”Interview Question
Section titled “Interview Question”How would you troubleshoot a slow API? What metrics would you analyze?
I would troubleshoot top-down, starting with the API and drilling into dependencies.
flowchart LR
Client --> Gateway[API Gateway]
Gateway --> App[Spring Boot]
App --> DB[(Database)]
App --> Redis[(Redis)]
App --> External[External APIs]
App --> Trace[Distributed Tracing]
Trace --> Bottleneck[Identify Bottleneck]
7.1 API Metrics
Section titled “7.1 API Metrics”Analyze:
- P50 latency
- P95 latency
- P99 latency
- Requests per second
- Error rate
- Timeout rate
- Response payload size
P95/P99 are especially important because averages can hide slow requests.
7.2 Application Metrics
Section titled “7.2 Application Metrics”Check:
- CPU utilization
- Memory utilization
- GC pauses
- Thread-pool utilization
- Thread dumps
- Blocked threads
- Deadlocks
7.3 Database Metrics
Section titled “7.3 Database Metrics”Check:
- Slow SQL queries
- Query execution time
- Missing indexes
- Connection-pool exhaustion
- DB CPU
- Active connections
- Locks
- Deadlocks
7.4 External Dependencies
Section titled “7.4 External Dependencies”Check:
- Downstream API latency
- Timeouts
- Retry count
- HTTP connection-pool utilization
- Circuit-breaker state
7.5 Cache Metrics
Section titled “7.5 Cache Metrics”Check:
- Cache hit ratio
- Cache miss ratio
- Redis latency
- Evictions
- Memory usage
7.6 Infrastructure Metrics
Section titled “7.6 Infrastructure Metrics”Check:
- Network latency
- Load balancer metrics
- Pod CPU/memory
- Kubernetes scaling
- Container restarts
- Node resource pressure
7.7 Request Tracing
Section titled “7.7 Request Tracing”Use distributed tracing:
Client ↓Gateway ↓Spring Boot ↓Redis / DB ↓External ServiceThe objective is to determine where the latency was introduced.
Crisp Interview Answer
Section titled “Crisp Interview Answer”I first check P95/P99 latency and distributed traces, then drill into application, database, cache, downstream services, and infrastructure metrics to isolate the bottleneck. I then reproduce the issue with load testing and validate the fix with the same metrics.
8. REST vs GraphQL vs gRPC
Section titled “8. REST vs GraphQL vs gRPC”Quick Comparison
Section titled “Quick Comparison”| REST | GraphQL | gRPC | |
|---|---|---|---|
| Best for | Public APIs, web/mobile | Flexible UI data fetching | Internal microservices |
| Protocol | HTTP | HTTP | HTTP/2 |
| Data format | Usually JSON | JSON | Protocol Buffers |
| Performance | Good | Good, with query overhead | Very high |
| Contract | OpenAPI commonly used | GraphQL schema | .proto contract |
| Browser support | Excellent | Excellent | Limited directly; gRPC-Web may be required |
| Streaming | Limited | Supported | Excellent |
| Complexity | Low | Medium | Medium |
| Typical use | External/business APIs | Complex frontend | Service-to-service |
8.1 REST
Section titled “8.1 REST”REST is usually the default choice for business and public-facing APIs.
Choose REST when
Section titled “Choose REST when”- Building public APIs
- Supporting web/mobile clients
- Implementing CRUD operations
- Interoperability and simplicity are important
- APIs are resource-oriented
- Easy debugging is important
Example:
React / Mobile App | HTTPS | v Spring Boot API | +-- GET /customers/123 +-- POST /customers +-- PUT /customers/123 +-- DELETE /customers/123Advantages
Section titled “Advantages”- Simple
- Widely understood
- Excellent browser/client support
- Easy to test
- Strong HTTP ecosystem
- Good caching support
Limitations
Section titled “Limitations”Can cause:
- Over-fetching
- Under-fetching
- Multiple calls for complex screens
8.2 GraphQL
Section titled “8.2 GraphQL”GraphQL is useful when clients need flexible control over the data they retrieve.
Choose GraphQL when
Section titled “Choose GraphQL when”- Frontend screens require multiple resources
- Different clients need different fields
- You want to reduce over-fetching
- You want to reduce under-fetching
- UI requirements change frequently
- Frontend needs aggregated data
Example query:
query { customer(id: "123") { name email orders { id amount } payments { status } }}Architecture:
flowchart LR
UI[React Application] --> G[GraphQL API]
G --> C[Customer Service]
G --> O[Order Service]
G --> P[Payment Service]
Advantages
Section titled “Advantages”- Flexible queries
- Reduces over-fetching
- Can aggregate multiple services
- Strong schema and type system
- Good fit for complex frontend applications
Limitations
Section titled “Limitations”- More complex implementation
- More complicated caching
- Query complexity needs controls
- N+1 query problems can occur
- Authorization needs careful design
Interview Point
Section titled “Interview Point”GraphQL is not automatically faster than REST. Its main advantage is flexible data fetching.
8.3 gRPC
Section titled “8.3 gRPC”gRPC is well suited for high-performance service-to-service communication.
It commonly uses:
- HTTP/2
- Protocol Buffers
- Strongly typed contracts
- Binary serialization
- Streaming
Choose gRPC when
Section titled “Choose gRPC when”- Communicating between internal microservices
- Low latency is important
- High throughput is required
- Strong API contracts are important
- Streaming is required
- Services are controlled by the same organization
Example:
Order Service | gRPC | vInventory Service | gRPC | vPayment ServiceExample .proto contract:
service InventoryService { rpc CheckStock(StockRequest) returns (StockResponse);}Advantages
Section titled “Advantages”- High performance
- Compact binary serialization
- Strongly typed contracts
- Excellent streaming
- HTTP/2 multiplexing
- Good fit for internal microservices
Limitations
Section titled “Limitations”- Less browser-friendly
- Debugging is less straightforward
- Requires generated code
- Adds operational complexity
8.4 Decision Guide
Section titled “8.4 Decision Guide”flowchart TD
A[Choose API Style] --> B{Public or External API?}
B -->|Yes| R[REST]
B -->|No| C{Complex Frontend Data Fetching?}
C -->|Yes| G[GraphQL]
C -->|No| D{Internal Service-to-Service?}
D -->|Yes| E{Low Latency / High Throughput / Streaming?}
D -->|No| R
E -->|Yes| GR[gRPC]
E -->|No| R
8.5 Scenario-Based Choice
Section titled “8.5 Scenario-Based Choice”Public Customer API
Section titled “Public Customer API”Choice: REST
flowchart LR
Mobile[Mobile App] --> REST[REST API]
REST --> Spring[Spring Boot]
Why?
- Simple
- Easy to consume
- Excellent HTTP ecosystem
- Easy documentation
Complex React Dashboard
Section titled “Complex React Dashboard”Choice: GraphQL
flowchart LR
React[React Dashboard] --> GraphQL[GraphQL API]
GraphQL --> Users[Users]
GraphQL --> Orders[Orders]
GraphQL --> Payments[Payments]
Why?
The UI can request exactly the fields required.
Internal Microservices
Section titled “Internal Microservices”Choice: gRPC
flowchart LR
Order[Order Service] -->|gRPC| Inventory[Inventory Service]
Order -->|gRPC| Payment[Payment Service]
Why?
- Low latency
- Strong contract
- Efficient serialization
- Good service-to-service communication
8.6 Practical Architecture
Section titled “8.6 Practical Architecture”A system can use all three.
flowchart LR
WEB[React Web App] --> REST[REST API]
MOBILE[Mobile App] --> REST
ADMIN[Complex Admin UI] --> GRAPH[GraphQL API]
REST --> ORDER[Order Service]
GRAPH --> ORDER
ORDER -->|gRPC| INVENTORY[Inventory Service]
ORDER -->|gRPC| PAYMENT[Payment Service]
ORDER -->|gRPC| CUSTOMER[Customer Service]
Typical strategy:
- REST → External/public APIs
- GraphQL → Complex frontend aggregation
- gRPC → Internal high-performance service communication
8.7 Interview Answer
Section titled “8.7 Interview Answer”I would use REST as the default for public and business-facing APIs because it is simple, interoperable, and easy to consume. I would choose GraphQL when frontend clients need flexible or aggregated data and I want to reduce over-fetching or under-fetching. I would choose gRPC for high-performance internal service-to-service communication where strong contracts, low latency, and streaming are important.
9. Senior/Lead Interview Summary
Section titled “9. Senior/Lead Interview Summary”Performance
Section titled “Performance”Identify the bottleneck first using P95/P99 latency, metrics, logs and tracing. Optimize the application, database, cache, downstream calls and infrastructure based on evidence. Validate improvements through load testing.
Spring controls object creation and dependency management instead of application code creating dependencies directly.
Dependency Injection
Section titled “Dependency Injection”Dependencies are provided by Spring rather than being created by the consuming class. Constructor injection is generally preferred.
Bean Lifecycle
Section titled “Bean Lifecycle”Spring instantiates the bean, injects dependencies, runs initialization callbacks, makes the bean available, and runs destruction callbacks where applicable.
Singleton vs Prototype
Section titled “Singleton vs Prototype”Singleton gives one instance per Spring container. Prototype creates a new instance when requested from the container.
API Security
Section titled “API Security”Use OAuth2/OIDC with Spring Security, short-lived JWT access tokens, securely managed refresh tokens, proper authorization, HTTPS, rate limiting, validation, secure logging and appropriate CSRF/CORS controls.
Slow API
Section titled “Slow API”Start with P95/P99 latency and distributed tracing, then investigate application, database, cache, downstream services and infrastructure metrics.
API Style
Section titled “API Style”REST is the default for simple/public APIs, GraphQL is useful for flexible frontend data fetching, and gRPC is a strong choice for high-performance internal microservice communication.
Final Quick Revision
Section titled “Final Quick Revision”Spring Boot Performance | +-- Measure first +-- Optimize DB +-- Cache +-- Tune pools +-- Async processing +-- Resilience +-- Horizontal scaling +-- Observability
Spring Core | +-- IoC +-- Dependency Injection +-- Bean Lifecycle +-- Singleton / Prototype
API Security | +-- OAuth2 / OIDC +-- JWT +-- Refresh Tokens +-- Authorization +-- Session Management +-- HTTPS / CORS / CSRF +-- Rate Limiting
API Troubleshooting | +-- P95 / P99 +-- CPU / Memory / GC +-- Threads +-- DB +-- Cache +-- Downstream Services +-- Infrastructure +-- Distributed Tracing
API Selection | +-- REST → Public / simple APIs +-- GraphQL → Flexible frontend queries +-- gRPC → Internal high-performance calls