Production

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.

01
Environment

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. @PropertySource annotations
  • 6. Defaults
@ConfigurationProperties โ€” type-safe binding with validation. Prefer over @Value for groups of related properties. Catches typos at startup, not at runtime.
02
Secrets

Externalized Config

Never commit secrets โ€” passwords, API keys, DB credentials. Options by environment:

EnvironmentStrategy
Local devapplication-local.yml (gitignored)
CI/CDEnvironment variables
ProductionVault / 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.
03
Observability

Actuator

Production-ready endpoints baked in โ€” no extra code. Add spring-boot-starter-actuator and configure exposure.

EndpointWhat It Shows
/actuator/healthUP/DOWN + component health (DB, cache, disk)
/actuator/infoBuild version, git commit, custom properties
/actuator/metricsJVM, HTTP request counts, custom metrics via Micrometer
/actuator/envAll resolved config properties (sensitive โ€” lock down)
/actuator/loggersView and change log levels at runtime without restart
/actuator/httptraceLast 100 HTTP requests (useful for debugging)
GET /actuator/health { "status": "UP", โ† overall status "components": { "db": { "status": "UP" }, โ† DataSource check "redis": { "status": "UP" }, โ† Cache check "diskSpace": { "status": "UP" } โ† Disk check } }
Security: Never expose /actuator/env or /actuator/shutdown publicly. Use management.endpoints.web.exposure.include=health,info,metrics. Implement custom HealthIndicator for downstream service checks.
04
Performance

Caching

  • @EnableCaching on a @Configuration class
  • @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.

Gotcha: @Cacheable on a private method or called from within the same class is silently ignored โ€” AOP proxy bypass, same root cause as @Transactional.
05
Stability

Resilience Patterns

One slow downstream call can exhaust threads and cascade. Resilience4j provides four key patterns:

PatternWhat It DoesWhen to Use
Circuit BreakerStops calling a failing service after thresholdAny external HTTP call
RetryRetries on transient failures with backoffIdempotent operations only
Rate LimiterLimits call rate to downstream serviceThird-party APIs with rate limits
BulkheadIsolates threads per downstream servicePrevent one slow call from starving others
Circuit Breaker State Machine
CLOSED calls go through failure threshold OPEN calls fail fast wait interval HALF-OPEN success โ†’ CLOSED
06
Quality

Testing Strategy

TypeAnnotationWhat It LoadsUse For
Unit@ExtendWith(MockitoExtension)Nothing โ€” plain JavaService logic
Web slice@WebMvcTestOnly web layerController, validation
Data slice@DataJpaTestOnly JPA + H2Repository queries
Integration@SpringBootTestFull contextEnd-to-end flows
  • @MockBean registers in Spring context, @Mock is pure Mockito โ€” different lifecycle
  • Testcontainers โ€” real Postgres/MySQL in Docker. Use @DynamicPropertySource for JDBC URL.
  • Test slices are faster than @SpringBootTest โ€” use them for the bulk of your tests