SpringBoot方法超时抛出异常实现方案咨询(含Redis交互场景)
SpringBoot方法执行时长追踪与超时异常抛出方案
需求梳理
- 监控Redis交互方法
getValue的执行时间 - 当执行时长超过指定阈值时,无论方法执行是否成功都抛出异常
- 无需手动在业务代码中捕获结束时间,实现自动化的时长监控
实现方案:基于Spring AOP的无侵入式监控
用AOP切面织入时长监控逻辑,完全不修改原有业务方法的核心代码,同时满足超时即抛异常的要求。
1. 自定义超时监控注解
定义一个注解,用来标记需要监控的方法,并支持自定义超时阈值:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface TimeoutMonitor { // 超时阈值,单位:毫秒,默认1000ms long threshold() default 1000; }
2. 编写AOP切面类
通过环绕切面在方法执行前后记录时间,无论方法是否抛出异常(即使业务代码捕获了异常),都会在finally块中计算执行时长并判断是否超时:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Aspect @Component public class TimeoutMonitorAspect { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutMonitorAspect.class); @Around("@annotation(timeoutMonitor)") public Object monitorExecutionTime(ProceedingJoinPoint joinPoint, TimeoutMonitor timeoutMonitor) throws Throwable { long startTime = System.currentTimeMillis(); Object methodResult; try { // 执行原方法 methodResult = joinPoint.proceed(); } finally { // 计算执行时长,无论方法是否成功执行都会走到这里 long executionDuration = System.currentTimeMillis() - startTime; long threshold = timeoutMonitor.threshold(); if (executionDuration > threshold) { String methodSignature = joinPoint.getSignature().toShortString(); String errorMsg = String.format("Method %s executed for %d ms, exceeds threshold of %d ms", methodSignature, executionDuration, threshold); LOGGER.error(errorMsg); // 抛出自定义超时异常,上层可按需处理 throw new MethodTimeoutException(errorMsg); } } return methodResult; } }
3. 自定义超时异常类
创建专属的RuntimeException,方便上层调用方识别和处理超时场景:
public class MethodTimeoutException extends RuntimeException { public MethodTimeoutException(String message) { super(message); } }
4. 改造原有业务方法
只需在目标方法上添加自定义注解,设置对应的超时阈值即可:
import org.springframework.stereotype.Component; @Component public class CacheService { private static final Logger LOGGER = LoggerFactory.getLogger(CacheService.class); private final String className = CacheService.class.getSimpleName(); private final RedisJedisTemplate redisJedisTemplate; // 构造注入Redis模板 public CacheService(RedisJedisTemplate redisJedisTemplate) { this.redisJedisTemplate = redisJedisTemplate; } // 设置超时阈值为500毫秒,可根据业务调整 @TimeoutMonitor(threshold = 500) public CacheResponse getValue(String key) { try { return redisJedisTemplate.opsForValue().get(key); } catch (Exception e) { LOGGER.error("{}: Error fetching data with key {} {}", className, key, e.getMessage()); return null; } } }
方案优势
- 完全无侵入:业务代码无需修改时长监控逻辑,仅需添加注解
- 覆盖所有场景:无论方法执行成功还是捕获了异常,都会触发超时判断
- 灵活性高:每个方法可独立设置超时阈值,适配不同业务场景
内容的提问来源于stack exchange,提问作者Monish Das
相关产品推荐
相关产品推荐

