Configuring Redis for Servlet-Based Services and WebFlux Gateways in Microservices

In modern microservice architectures, Redis is widely used for caching, distributed locking, session storage, and rate limiting. However, the way you interact with Redis differs significantly between a traditional Servlet‑based service (blocking) and a WebFlux‑based gateway (non‑blocking). This guide explains both approaches and provides ready‑to‑use configuration and code samples.

Understanding the Architectural Differences

Servlet containers follow a synchronous, blocking I/O model. Each request occupies a thread until all I/O operations complete, which can lead to thread‑pool exhaustion under high concurrency.

WebFlux, on the other hand, uses an asynchronous, non‑blocking I/O model. A single thread can handle many requests concurrently; when an I/O operation (like a Redis call) is in flight, the thread is freed to process other tasks. This makes WebFlux ideal for gateway scenarios that must handle tohusands of simultaneous connections.

  1. Using Redis in a Servlet‑Based Microservice

1.1 Dependencies (Maven)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

1.2 Application Configuration

spring:
  redis:
    host: localhost
    port: 6379
    password: yourpassword
    lettuce:
      pool:
        max-active: 16
        max-idle: 8
        min-idle: 4
        max-wait: 2000ms

1.3 Synchronous Redis Template

Spring Data Redis provides RedisTemplate and StringRedisTemplate for synchronous operations. Below is a utility class that performs common tasks:

@Component
public class ServletRedisHelper {

    private final StringRedisTemplate template;

    public ServletRedisHelper(StringRedisTemplate template) {
        this.template = template;
    }

    public void storeString(String key, String value) {
        template.opsForValue().set(key, value);
    }

    public void storeStringWithTtl(String key, String value, long ttlSeconds) {
        template.opsForValue().set(key, value, ttlSeconds, TimeUnit.SECONDS);
    }

    public String fetchString(String key) {
        return template.opsForValue().get(key);
    }

    public boolean deleteKey(String key) {
        return Boolean.TRUE.equals(template.delete(key));
    }

    public boolean checkExists(String key) {
        return Boolean.TRUE.equals(template.hasKey(key));
    }

    public boolean acquireLock(String lockKey, String ownerId, long ttlSeconds) {
        return Boolean.TRUE.equals(
                template.opsForValue().setIfAbsent(lockKey, ownerId, ttlSeconds, TimeUnit.SECONDS));
    }

    public boolean releaseLock(String lockKey, String ownerId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        Long result = template.execute(redisScript, Collections.singletonList(lockKey), ownerId);
        return Long.valueOf(1).equals(result);
    }
}

1.4 Caching with Annotations

Enable caching in a configuration class:

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory cf) {
        RedisCacheConfiguration defaults = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(15))
                .disableCachingNullValues()
                .serializeValuesWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(
                        new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(cf)
                .cacheDefaults(defaults)
                .build();
    }
}

Then use the annotations in your service:

@Service
public class OrderService {

    @Cacheable(value = "orders", key = "#orderId")
    public Order findOrderById(Long orderId) {
        // database call
        return orderRepository.findById(orderId).orElse(null);
    }

    @CachePut(value = "orders", key = "#order.id")
    public Order updateOrder(Order order) {
        orderRepository.save(order);
        return order;
    }

    @CacheEvict(value = "orders", key = "#orderId")
    public void removeOrder(Long orderId) {
        orderRepository.deleteById(orderId);
    }
}

  1. Using Redis in a WebFlux Gateway

Spring Boot provides the spring-boot-starter-data-redis-reactive starter for reactive Redis access.

2.1 Dependencies (Maven)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2.2 Application Configuration

Configuration is identical to the Servlet case:

spring:
  redis:
    host: localhost
    port: 6379
    password: yourpassword
    lettuce:
      pool:
        max-active: 16
        max-idle: 8
        min-idle: 4

2.3 Reactive Redis Template

@Service
public class ReactiveRedisService {

    private final ReactiveStringRedisTemplate reactiveTemplate;

    public ReactiveRedisService(ReactiveStringRedisTemplate reactiveTemplate) {
        this.reactiveTemplate = reactiveTemplate;
    }

    public Mono<Boolean> setValue(String key, String value) {
        return reactiveTemplate.opsForValue().set(key, value);
    }

    public Mono<String> getValue(String key) {
        return reactiveTemplate.opsForValue().get(key);
    }

    public Mono<Boolean> setValueWithTtl(String key, String value, Duration ttl) {
        return reactiveTemplate.opsForValue().set(key, value, ttl);
    }

    public Mono<Long> removeKey(String key) {
        return reactiveTemplate.delete(key);
    }
}

2.4 Using Redis in a Gateway Filter

The following example shows a custom global filter that validates a JWT token stored in Redis:

@Component
public class JwtValidationFilter implements GlobalFilter, Ordered {

    private final ReactiveRedisService redisService;

    public JwtValidationFilter(ReactiveRedisService redisService) {
        this.redisService = redisService;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        List<String> authHeader = exchange.getRequest().getHeaders().get("Authorization");
        if (authHeader == null || authHeader.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String token = authHeader.get(0).replace("Bearer ", "");
        return redisService.getValue("jwt:" + token)
                .flatMap(userId -> {
                    if (userId != null) {
                        // attach user info to exchange attributes
                        exchange.getAttributes().put("userId", userId);
                        return chain.filter(exchange);
                    }
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                    return exchange.getResponse().setComplete();
                })
                .switchIfEmpty(Mono.defer(() -> {
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                    return exchange.getResponse().setComplete();
                }));
    }

    @Override
    public int getOrder() {
        return -100;
    }
}

  1. Key Differences Between the Two Approaches

Aspect Servlet (Blocking) WebFlux (Non‑blocking)
Return types Direct values (String, Object) Mono / Flux
Thread usage Thread blocked during Redis call Thread released, can handle other requests
Best suited for Complex business logic, lower concurrency High concurrency, I/O‑intensive gateways
Spring starter spring-boot-starter-data-redis spring-boot-starter-data-redis-reactive
  1. Conclusion

Both Servlet‑based services and WebFlux gateways can use Redis effectively, but the choice of client and programming model must align with the underlying I/O model. For traditional microservices, RedisTemplate offers a simple synchronous API. For reactive gateways, ReactiveRedisTemplate integrates seamlessly with the non‑blocking paradigm, enabling high throughput under heavy load.

Tags: Redis Spring Boot WebFlux microservices servlet

Posted on Sun, 17 May 2026 11:14:36 +0000 by feckless