đ± Spring â Core, Boot, Data, Security, Cloud, Observability
Guide IDEO-Lab : Spring âen productionâ (IoC, Boot autoconfig, REST, Data, Security, transactions, tests, perf, cloud-native).
Vue dâensemble Spring
ĂcosystĂšme, modules, philosophie : conventions, DI, layering.
CoreEcosystemDIIoC / DI & Bean Lifecycle
Container, scopes, proxies, lifecycle hooks, profiles.
IoCBeanProfilesSpring Boot
Autoconfiguration, starters, properties, actuators, packaging.
BootAutoconfigActuatorSpring Web / REST
@RestController, validation, errors, OpenAPI, versioning API.
MVCRESTValidationSpring Data
Repositories, JPA, paging, specs, transactions, auditing.
DataJPARepositoryTransactions & Cohérence
@Transactional, propagation, isolation, read-only, piĂšges proxy.
TXPropagationIsolationSpring Security
AuthN/AuthZ, filters, JWT, sessions, CSRF, method security.
SecurityAuthJWTConfiguration
application.yml, profiles, secrets, config server, feature flags.
ConfigProfilesSecretsObservability
Actuator, metrics, tracing, logs corrélés, health checks.
ActuatorMetricsTracingTests
@SpringBootTest, slices, Testcontainers, MockMvc/WebTestClient.
JUnitTestcontainersSlicesPerformance & Scalabilité
N+1, cache, pooling, async, backpressure, tuning GC.
PerfN+1PoolingSpring Cloud
Config, discovery, gateway, resilience, distributed patterns.
CloudGatewayResilienceCheat-sheet Spring
Rappels express : DI, REST, Data, Security, Actuator, tests.
cheatbest practicesSpring = framework + conventions
Spring est un Ă©cosystĂšme : le cĆur (IoC/DI) + des modules (Web, Data, Security, MessagingâŠ). Lâobjectif : construire des applications testables, maintenables, observables.
Pipeline ârequest â business â DBâ
HTTP request -> Controller -> Service (transaction boundary) -> Repository -> Database <- Response
Les erreurs classiques viennent dâune frontiĂšre TX mal placĂ©e + un fetch JPA non maĂźtrisĂ©.
Modules fréquents
| Module | Usage | Ă retenir |
|---|---|---|
| Spring Core | DI / container | Scopes, proxies, lifecycle |
| Spring Boot | Autoconfig | Starters + properties + Actuator |
| Spring Web | REST/MVC | Validation + exceptions + OpenAPI |
| Spring Data | Repositories | Paging/specs + transactions |
| Spring Security | Auth | Filter chain + method security |
| Spring Cloud | Distributed | Gateway + config + resilience |
Architecture âproduction-friendlyâ
- Layering : Controller â Service â Repository.
- DTO en API (Ă©viter dâexposer directement des entitĂ©s JPA).
- Observability : metrics + traces + logs corrélés + health checks.
- Configuration : profiles + secrets + validation.
- Tests : slices + Testcontainers pour les composants critiques.
Constructor injection (recommandé)
// English-only sample
@Service
public class BillingService {
private final PaymentGateway gateway;
public BillingService(PaymentGateway gateway) {
this.gateway = gateway;
}
}Constructor injection = immutabilité + testabilité + dépendances explicites.
Qualifier / primary
// English-only sample
@Bean
@Primary
public PaymentGateway stripeGateway() { return new StripeGateway(); }
@Bean
public PaymentGateway mockGateway() { return new MockGateway(); }Quand plusieurs beans matchent une interface : @Primary, @Qualifier, ou @Profile.
Scopes (lâessentiel)
| Scope | Durée | Usage |
|---|---|---|
| singleton | 1 par container | services stateless |
| prototype | nouvelle instance | objets stateful court |
| request | par requĂȘte HTTP | web context |
| session | par session | rare en API stateless |
Bean lifecycle (hooks utiles)
// English-only sample
@Bean(initMethod = "start", destroyMethod = "stop")
public Worker worker() { return new Worker(); }
@PostConstruct
public void init() { /* init */ }
@PreDestroy
public void shutdown() { /* cleanup */ }En prod : préférer des composants stateless + ressources explicites (DataSource, HTTP client).
Ce que Boot fait (et ne fait pas)
- Autoconfigure selon le classpath + properties.
- Fournit des Starters (dépendances cohérentes).
- Expose Actuator pour santé/metrics.
- Ne remplace pas lâarchitecture : TX, fetch, sĂ©curitĂ© restent ton job.
Main minimal
// English-only sample
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}Debug autoconfig (indispensable)
# English-only sample debug=true
Le âcondition evaluation reportâ explique pourquoi un bean a Ă©tĂ© créé (ou non).
application.yml : pattern sain
# English-only sample
spring:
application:
name: demo
datasource:
url: jdbc:postgresql://db:5432/app
username: app
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
open-in-view: false
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheusopen-in-view: false pour éviter le lazy loading en dehors du scope service/TX.Actuator : endpoints essentiels
| Endpoint | Usage | Note sécu |
|---|---|---|
| /actuator/health | readiness/liveness | exposer sanitized |
| /actuator/metrics | KPIs | limiter |
| /actuator/prometheus | scraping | auth/network |
| /actuator/env | debug config | souvent à désactiver |
# English-only sample management.endpoint.health.probes.enabled=true management.endpoint.health.show-details=never
REST minimal (DTO)
// English-only sample
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
private final CustomerService service;
public CustomerController(CustomerService service) {
this.service = service;
}
@GetMapping("/{id}")
public CustomerDto get(@PathVariable long id) {
return service.getCustomer(id);
}
}API versioning (reco)
- Version dans lâURL (
/v1/) ou header. - DTO versionnĂ©s (ne pas âcasserâ les clients).
- Backwards compatibility + deprecation policy.
Bean Validation sur DTO
// English-only sample
public record CreateCustomerRequest(
@NotBlank @Size(max = 120) String name,
@Email @NotBlank String email
) {}
@PostMapping
public CustomerDto create(@Valid @RequestBody CreateCustomerRequest req) {
return service.createCustomer(req);
}Valider cÎté API + contraintes DB (unique, not null) = robustesse.
Exception mapping propre
// English-only sample
@RestControllerAdvice
public class ApiErrors {
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map notFound(NotFoundException e) {
return Map.of("error", "NOT_FOUND", "message", e.getMessage());
}
} Standardiser les erreurs = meilleure observabilité + intégration clients.
Repository minimal
// English-only sample public interface CustomerRepository extends JpaRepository{ Optional findByEmail(String email); }
Top pour CRUD. Sur les cas complexes : @Query, Specifications, ou Querydsl.
Auditing (timestamps)
// English-only sample
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Customer {
@CreatedDate private Instant createdAt;
@LastModifiedDate private Instant updatedAt;
}Pense aussi aux triggers DB si la donnĂ©e doit ĂȘtre âsource of truthâ cĂŽtĂ© DB.
Pagination + sorting
// English-only sample Pagepage = repo.findAll(PageRequest.of(0, 50, Sort.by("name").ascending()));
Specifications (filtres dynamiques)
// English-only sample public static SpecificationhasStatus(String status) { return (root, query, cb) -> cb.equal(root.get("status"), status); }
N+1 : le vrai sujet Data/JPA
- Ne pas exposer les entités directement en API.
- Préférer DTO projections / fetch plan explicite.
- Désactiver Open Session In View (Boot) et charger ce qui est nécessaire dans la TX.
# English-only sample spring.jpa.open-in-view=false
TX au niveau Service
// English-only sample
@Service
public class OrderService {
private final OrderRepository repo;
public OrderService(OrderRepository repo) { this.repo = repo; }
@Transactional
public OrderDto placeOrder(CreateOrderRequest req) {
Order o = new Order();
// build aggregate
repo.save(o);
return map(o);
}
}Isolation & locks
Lâisolation est DB-level. Spring te permet de dĂ©clarer lâintention, mais le SGBD dĂ©cide du comportement rĂ©el.
// English-only sample @Transactional(isolation = Isolation.READ_COMMITTED)
Propagation : usage typique
| Propagation | IdĂ©e | Cas dâusage |
|---|---|---|
| REQUIRED | join or create | par défaut |
| REQUIRES_NEW | new TX | audit/outbox, éviter rollback global |
| SUPPORTS | optional | lecture, utilitaires |
// English-only sample
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void writeAudit(AuditEvent e) { /* ... */ }PiÚges fréquents
- Self-invocation : un appel interne nâactive pas le proxy â pas de TX.
- Read-only : hint, pas un âno-write firewallâ.
- Large TX : locks longs + timeouts + mémoire (persistence context).
La âfilter chainâ = le cĆur
Spring Security applique une chaĂźne de filtres avant dâatteindre tes controllers : authentification, autorisation, gestion session, CSRF, headers, etc.
// English-only sample
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.anyRequest().authenticated()
)
.build();
}JWT (API stateless) â pattern
- Issuer, audience, expiration, rotation keys.
- Scopes/roles normalisés.
- Reject tokens on clock skew too large.
// English-only sample http .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
Hardening checklist
- CSRF activé sur apps stateful, désactivé uniquement si API stateless maßtrisée.
- Headers : CSP, HSTS, X-Content-Type-Options.
- Limiter lâexposition Actuator (auth + rĂ©seau).
- Logs dâauth : corrĂ©lation request_id + user_id.
Profiles
# English-only sample spring.profiles.active=prod
# English-only sample
spring:
config:
activate:
on-profile: prodSĂ©parer dev/stage/prod et Ă©viter de âtogglerâ Ă la main sur des serveurs.
Secrets : rĂšgles simples
- Jamais en dur dans Git.
- Variables dâenvironnement + secret manager (Vault/Cloud provider).
- Rotation + audit + least privilege.
# English-only sample
spring.datasource.password=${DB_PASSWORD}Patterns robustes
| Pattern | But | Note |
|---|---|---|
| ConfigurationProperties | config typed | validation possible |
| Feature flags | rollout | observability + kill switch |
| Config server | centralize | cache + fallback |
// English-only sample
@ConfigurationProperties(prefix = "app.billing")
public record BillingProps(int retryMax) {}KPIs Ă monitorer
- HTTP latency p95/p99, error rate, throughput.
- DB pool saturation, slow queries, N+1 detection (query count).
- GC pauses, heap usage, CPU throttling.
# English-only sample management.endpoints.web.exposure.include=health,metrics,prometheus
Tracing distribué
Objectif : suivre une requĂȘte bout-en-bout via trace_id et corrĂ©ler logs + spans + DB calls.
# English-only sample
logging.pattern.level=%5p [trace=%X{traceId:-} span=%X{spanId:-}]Readiness / Liveness
# English-only sample management.endpoint.health.probes.enabled=true management.health.livenessState.enabled=true management.health.readinessState.enabled=true
StratĂ©gie test âproâ
| Niveau | But | Outil |
|---|---|---|
| Unit | logique pure | JUnit + mocks |
| Slice | focus layer | @WebMvcTest, @DataJpaTest |
| Integration | stack complĂšte | @SpringBootTest |
| DB real | SQL/locks | Testcontainers |
@WebMvcTest
// English-only sample
@WebMvcTest(CustomerController.class)
class CustomerControllerTest {
@Autowired MockMvc mvc;
@MockBean CustomerService service;
}@DataJpaTest
// English-only sample
@DataJpaTest
class CustomerRepositoryTest {
@Autowired CustomerRepository repo;
}DB ârĂ©elleâ en test
// English-only sample
@Testcontainers
class DbIT {
@Container static PostgreSQLContainer db = new PostgreSQLContainer<>("postgres:16");
}Indispensable pour N+1, plans, locks, isolation, migrations.
La perf Spring = souvent la perf DB
- N+1 â requĂȘtes multipliĂ©es, latence.
- Indexes manquants â full scans.
- Transactions trop longues â contention.
Connection pool (Hikari) : points clés
- pool trop petit â timeouts / queueing.
- pool trop grand â surcharge DB.
- mesurer active/idle, wait time, saturation.
# English-only sample spring.datasource.hikari.maximumPoolSize=20 spring.datasource.hikari.connectionTimeout=3000
Cache & async (prudence)
- Cache uniquement si stratĂ©gie dâinvalidation dĂ©finie.
- Async utile pour I/O (HTTP) mais attention au backpressure.
- Pour débit : limiter concurrency + timeouts + retries.
// English-only sample
@Cacheable("customerById")
public CustomerDto getCustomer(long id) { /* ... */ }
@Async
public CompletableFuture sync() { /* ... */ } Patterns distribués
- Config centralisée + cache local + fallback.
- Service discovery (ou DNS/K8s service).
- Central auth (JWT/OIDC) + policy.
- Rate limiting + circuit breakers.
API Gateway : rĂŽle
- Auth edge, routing, retries, rate limit, WAF-like.
- Observability centralisée (traces, headers).
# English-only sample (concept)
routes:
- id: api
uri: http://service
predicates:
- Path=/api/**Resilience
| Mécanisme | But | Note |
|---|---|---|
| Timeout | bound latency | obligatoire |
| Retry | transient errors | sur idempotent |
| Circuit breaker | stop bleeding | évite cascade |
| Bulkhead | limit concurrency | protéger pool |
DI / Boot / Web
// English-only quick notes Prefer constructor injection Keep controllers thin Use DTOs for API Disable open-in-view in prod Standardize error responses
Data / TX
// English-only quick notes @Transactional at service level Avoid long transactions Watch N+1 (query count per request) Use paging + DTO projections Use optimistic locking + retries
Security / Observability
// English-only quick notes Use stateless JWT for APIs Lock down actuator endpoints Enable metrics + tracing + correlated logs Expose readiness/liveness probes
Config / Tests
// English-only quick notes Profiles: dev/stage/prod Secrets via env/secret manager Slices for fast tests Testcontainers for real DB behavior
