Profiles, Actuator, Resilience
What separates a working local app from a production-ready service. The 20% of config decisions that cover 80% of real scenarios.
Profiles & Configuration
application.yml for base config, application-{profile}.yml for environment overrides.
Set spring.profiles.active via environment variable in production.
- 1. Command line args (
--server.port=9090) - 2. Environment variables (
SERVER_PORT) - 3.
application-{profile}.yml - 4.
application.yml - 5.
@PropertySourceannotations - 6. Defaults
@ConfigurationProperties โ type-safe binding with validation. Prefer over @Value
for groups of related properties. Catches typos at startup, not at runtime.
Externalized Config
Never commit secrets โ passwords, API keys, DB credentials. Options by environment:
| Environment | Strategy |
|---|---|
| Local dev | application-local.yml (gitignored) |
| CI/CD | Environment variables |
| Production | Vault / AWS Secrets Manager / K8s Secrets |
@ConfigurationProperties with @Validated โ catch missing required config at startup, not at runtime.
Spring Cloud Config Server is available for centralised config in microservices.
Actuator
Production-ready endpoints baked in โ no extra code. Add spring-boot-starter-actuator and configure exposure.
| Endpoint | What It Shows |
|---|---|
/actuator/health | UP/DOWN + component health (DB, cache, disk) |
/actuator/info | Build version, git commit, custom properties |
/actuator/metrics | JVM, HTTP request counts, custom metrics via Micrometer |
/actuator/env | All resolved config properties (sensitive โ lock down) |
/actuator/loggers | View and change log levels at runtime without restart |
/actuator/httptrace | Last 100 HTTP requests (useful for debugging) |
/actuator/env or /actuator/shutdown publicly.
Use management.endpoints.web.exposure.include=health,info,metrics.
Implement custom HealthIndicator for downstream service checks.
Caching
@EnableCachingon a@Configurationclass@Cacheable("users")โ on read methods. Key derived from method params by default.@CacheEvictโ invalidate cache on write. Call on save/delete methods.@CachePutโ update cache entry. Less common.
Default cache: ConcurrentHashMap (in-memory, no TTL, not distributed).
Production: Redis (spring-boot-starter-data-redis) โ supports TTL and distributed caching.
@Cacheable on a private method or called from within the same class
is silently ignored โ AOP proxy bypass, same root cause as @Transactional.
Resilience Patterns
One slow downstream call can exhaust threads and cascade. Resilience4j provides four key patterns:
| Pattern | What It Does | When to Use |
|---|---|---|
| Circuit Breaker | Stops calling a failing service after threshold | Any external HTTP call |
| Retry | Retries on transient failures with backoff | Idempotent operations only |
| Rate Limiter | Limits call rate to downstream service | Third-party APIs with rate limits |
| Bulkhead | Isolates threads per downstream service | Prevent one slow call from starving others |
Testing Strategy
| Type | Annotation | What It Loads | Use For |
|---|---|---|---|
| Unit | @ExtendWith(MockitoExtension) | Nothing โ plain Java | Service logic |
| Web slice | @WebMvcTest | Only web layer | Controller, validation |
| Data slice | @DataJpaTest | Only JPA + H2 | Repository queries |
| Integration | @SpringBootTest | Full context | End-to-end flows |
@MockBeanregisters in Spring context,@Mockis pure Mockito โ different lifecycle- Testcontainers โ real Postgres/MySQL in Docker. Use
@DynamicPropertySourcefor JDBC URL. - Test slices are faster than
@SpringBootTestโ use them for the bulk of your tests