spring boot 全局异常处理可以通过配置 @controlleradvice 捕获 lettuce 连接异常,核心做法是拦截 io.lettuce.core.redisconnectionexception 及其子类。由于 lettuce 默认使用异步非阻塞模型,同步调用(如 stringredistemplate.opsforvalue().get())在底层会阻塞等待结果,当连接断开或超时时会抛出 redisconnectionexception 或 timeoutexception。在全局异常处理器中显式声明对这些异常的捕获,即可统一返回错误信息或执行降级逻辑。

StringRedisTemplate 同步操作抛出什么异常
在使用 StringRedisTemplate 进行同步数据读写时,Lettuce 客户端会在底层连接不可用时抛出 io.lettuce.core.RedisConnectionException。这是最直接的连接异常类型,通常发生在服务器重启、网络中断或连接池耗尽且无法获取新连接时。该异常继承自 RedisException,因此在全局异常处理中捕获它比捕获通用的 RuntimeException 更精准。

import org.springframework.data.redis.connection.RedisConnectionException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RedisConnectionException.class)
public String handleRedisConnectionException(RedisConnectionException ex) {
// 记录日志
System.err.println("Redis connection lost: " + ex.getMessage());
return "Service Unavailable: Redis Connection Failed";
}
}
上述代码定义了一个全局异常处理器。当控制器中的任何方法抛出 RedisConnectionException 时,Spring MVC 会将其路由到 handleRedisConnectionException 方法。这里直接返回一个字符串作为响应体,实际项目中可返回自定义的 JSON 结构。注意,如果使用的是 RedisTemplate,异常类型完全一致,因为 StringRedisTemplate 只是其泛型特化。
如何区分连接异常与超时异常
Lettuce 的连接问题不仅表现为 RedisConnectionException,还常以 java.util.concurrent.TimeoutException 的形式出现。这通常由 timeout 参数触发,例如在 execute 方法中设置了较短的等待时间,或者连接池中的连接处于“僵死”状态,客户端尝试复用但长时间无响应。虽然两者都源于连接层问题,但 TimeoutException 可能来自 CompletableFuture 的阻塞等待,而 RedisConnectionException 更多指向物理连接的中断或拒绝。在全局处理中,建议同时捕获这两个异常,因为它们往往需要相同的降级策略(如返回缓存数据或提示服务繁忙)。

import java.util.concurrent.TimeoutException;
import org.springframework.data.redis.connection.RedisConnectionException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({RedisConnectionException.class, TimeoutException.class})
public String handleRedisExceptions(Exception ex) {
if (ex instanceof RedisConnectionException) {
return "Redis Connection Lost";
} else if (ex instanceof TimeoutException) {
return "Redis Operation Timed Out";
}
return "Unknown Error";
}
}
这段代码展示了如何处理两种不同的异常。通过在一个 @ExceptionHandler 中指定多个异常类,可以简化代码结构。在方法内部,通过 instanceof 判断具体类型,从而提供更有针对性的错误消息。这种处理方式确保了无论是连接彻底断开还是操作超时,用户都能得到明确的反馈,而不是默认的 500 错误页面。在实际应用中,还可以结合重试机制或熔断器来进一步增强系统的健壮性。
连接恢复后异常是否还会被捕获
即使 Redis 连接已经恢复,之前因连接中断而挂起的请求仍会抛出异常并被全局处理器捕获。这是因为 StringRedisTemplate 的同步方法是阻塞式的,它在发起请求时就绑定了当前的线程和上下文。如果在该线程等待期间连接断开,异常会在当前线程中抛出,与后续连接的恢复状态无关。这意味着全局异常处理器必须能够处理这些“历史遗留”的异常,而不能依赖连接状态的实时检查。对于长轮询或高并发场景,建议设置合理的 command-timeout 和 shutdown-timeout,以减少此类异常的发生频率。











