DEV Community

Cover image for **5 Essential Spring Boot Production Optimization Techniques for Peak Performance and Cost Savings**
Aarav Joshi
Aarav Joshi

Posted on

**5 Essential Spring Boot Production Optimization Techniques for Peak Performance and Cost Savings**

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

Optimizing Spring Boot Applications for Production Environments

Spring Boot simplifies Java development, but production deployments demand specific adjustments. I've found that neglecting these optimizations leads to sluggish startups and inflated cloud bills. Let me share five practical techniques that balance performance with maintainability.

Lazy Initialization for Faster Startups

Spring Boot traditionally creates all beans at startup. This can cause delays, especially with complex dependency graphs. Lazy initialization postpones bean creation until first use. I've seen applications start 40% faster using this method. Configure it via properties:

# application.properties
spring.main.lazy-initialization=true
Enter fullscreen mode Exit fullscreen mode

Or programmatically:

public static void main(String[] args) {
    new SpringApplicationBuilder(MyApp.class)
        .lazyInitialization(true)
        .run(args);
}
Enter fullscreen mode Exit fullscreen mode

Be mindful: First requests may experience slight latency as dependencies initialize. I recommend combining this with connection pooling to mitigate the impact. In memory-constrained environments like Kubernetes pods, this technique significantly reduces initial resource consumption.

Securing Actuator Endpoints

Spring Boot Actuator provides crucial production insights but exposes risks if misconfigured. I always restrict endpoints and implement role-based access. This YAML configuration demonstrates secure practices:

management:
  endpoints:
    web:
      exposure:
        include: health,info
      base-path: /internal
  endpoint:
    health:
      show-details: when_authorized
      roles: ADMIN
    shutdown:
      enabled: false
Enter fullscreen mode Exit fullscreen mode

Customizing the base path (/internal) obscures endpoints from automated scanners. For critical systems, I add IP whitelisting:

@Configuration
class ActuatorSecurity extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/internal/**")
            .authorizeRequests()
            .antMatchers("/internal/health").permitAll()
            .antMatchers("/internal/**").hasRole("ADMIN")
            .and().httpBasic();
    }
}
Enter fullscreen mode Exit fullscreen mode

Building Meaningful Health Checks

Default health indicators often lack context. Creating custom checks provides actionable insights. This storage health indicator helped me prevent outages during peak traffic:

@Component
public class StorageHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        Path storagePath = Paths.get("/app/uploads");
        long freeSpace = storagePath.toFile().getFreeSpace();

        if (freeSpace > 100_000_000) {
            return Health.up()
                .withDetail("freeBytes", freeSpace)
                .build();
        } else {
            return Health.down()
                .withDetail("freeBytes", freeSpace)
                .withException(new IOException("Low disk space"))
                .build();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Combine with third-party integrations:

@Component
public class PaymentServiceHealthIndicator implements HealthIndicator {
    @Autowired
    private PaymentServiceClient client;

    @Override
    public Health health() {
        try {
            client.checkStatus();
            return Health.up().build();
        } catch (ServiceDownException ex) {
            return Health.down().withException(ex).build();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Type-Safe Configuration Management

Configuration mishaps cause frequent production issues. Spring Boot's @ConfigurationProperties prevents typos and enables validation:

@ConfigurationProperties(prefix = "app.redis")
@Validated
public class RedisConfig {
    @NotBlank
    private String host;

    @Min(1024)
    @Max(65535)
    private int port;

    @DurationUnit(ChronoUnit.SECONDS)
    private Duration timeout = Duration.ofSeconds(3);

    // Getters and setters
}
Enter fullscreen mode Exit fullscreen mode

Enable metadata generation in pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Now your IDE autocompletes properties:

# application.properties
app.redis.host=redis.prod.example.com
app.redis.port=6380
app.redis.timeout=5s
Enter fullscreen mode Exit fullscreen mode

Optimizing Docker Builds

Inefficient Docker builds waste CI/CD resources. Layer optimization dramatically reduces image size and build times:

FROM eclipse-temurin:17-jdk as builder
WORKDIR /app
COPY mvnw ./
COPY .mvn/ ./.mvn/
COPY pom.xml ./
RUN ./mvnw dependency:go-offline

COPY src ./src
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=builder /app/target/*.jar ./app.jar
ENTRYPOINT ["java","-jar","/app/app.jar"]
Enter fullscreen mode Exit fullscreen mode

For advanced optimization, use Spring Boot's layer tools:

FROM eclipse-temurin:17-jdk as builder
WORKDIR /app
COPY . .
RUN ./mvnw package

FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=builder /app/target/dependencies/ ./
COPY --from=builder /app/target/spring-boot-loader/ ./
COPY --from=builder /app/target/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
Enter fullscreen mode Exit fullscreen mode

This separates dependencies from application code. Changing business logic doesn't rebuild dependencies, reducing CI times by 70% in my projects.

Native Compilation with GraalVM

For extreme performance demands, native compilation reduces startup time from seconds to milliseconds. Configure Maven:

<build>
    <plugins>
        <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
            <version>0.9.27</version>
            <executions>
                <execution>
                    <id>build-native</id>
                    <goals><goal>compile</goal></goals>
                    <phase>package</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Enter fullscreen mode Exit fullscreen mode

Build with:

mvn -Pnative package
Enter fullscreen mode Exit fullscreen mode

Key considerations:

  • Use @NativeHint for reflection configuration
  • Test thoroughly with native profile
  • Memory usage drops by 50-70%
  • Startup times often improve by 10x

Database Connection Tuning

Connection management significantly impacts performance. Configure HikariCP for optimal throughput:

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      idle-timeout: 30000
      max-lifetime: 120000
      connection-timeout: 5000
      leak-detection-threshold: 60000
Enter fullscreen mode Exit fullscreen mode

Validate with Actuator metrics:

curl http://localhost:8080/internal/metrics/hikari.connections.active
Enter fullscreen mode Exit fullscreen mode

Cache Optimization Strategies

Caching reduces database load but requires careful sizing. Combine Caffeine with Redis:

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public Caffeine<Object, Object> caffeineConfig() {
        return Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(1000);
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration
            .defaultCacheConfig()
            .entryTtl(Duration.ofHours(1));

        return new RedisCacheManager(
            RedisCacheWriter.lockingRedisCacheWriter(factory),
            config
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Logging Performance Considerations

Logging often becomes a hidden performance drain. Use asynchronous logging with Logback:

<configuration>
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>10000</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <appender-ref ref="FILE" />
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/app.log</file>
        <encoder>
            <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="ASYNC" />
    </root>
</configuration>
Enter fullscreen mode Exit fullscreen mode

Set production logging levels in application.properties:

logging.level.root=WARN
logging.level.com.myapp=INFO
logging.level.org.springframework.web=ERROR
Enter fullscreen mode Exit fullscreen mode

JVM Runtime Tuning

JVM flags significantly impact performance. For containerized environments, always set:

java -XX:+UseContainerSupport \
     -XX:MaxRAMPercentage=75.0 \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -jar application.jar
Enter fullscreen mode Exit fullscreen mode

Key parameters:

  • UseContainerSupport: Respects Kubernetes memory limits
  • MaxRAMPercentage: Prevents OOM kills
  • G1GC: Balances throughput and latency

Final Implementation Checklist

Before deploying:

  1. Validate lazy initialization impact with ApplicationStartup
  2. Scan exposed Actuator endpoints
  3. Test health checks under failure conditions
  4. Verify configuration metadata in IDE
  5. Profile Docker image with dive
  6. Load-test with 2x expected traffic
  7. Monitor GC behavior with VisualVM

These techniques consistently yield applications that start faster, use fewer resources, and handle real-world loads gracefully. The balance between development speed and runtime efficiency defines production-ready Spring Boot applications.

📘 Checkout my latest ebook for free on my channel!

Be sure to like, share, comment, and subscribe to the channel!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | Java Elite Dev | Golang Elite Dev | Python Elite Dev | JS Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)