spring aop实现接口超时处理组件

文章目录

实现思路

  1. 这里使用FutureTask,它通过get方法以阻塞的方式获取执行结果,并设定超时时间:
java 复制代码
public V get() throws InterruptedException, ExecutionException ;

public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException ;
  1. 利用spring aop解耦业务
  2. 定义业务异常信息

实现代码

定义注解:

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
public @interface TimeoutCheck {

    /**
     * 超时时间,默认5秒
     */
    long timeout() default 5L;

    /**
     * 超时单位,默认秒
     */
    TimeUnit unit() default TimeUnit.SECONDS;

    /**
     * 超时后是否销毁线程
     */
    boolean destroy() default true;
}

这里有一个destroy()的方法,因为我们在执行时开独立线程处理,所以这个方法是为了在超时后,用来判断是否销毁还在执行的线程;

定义异常:

注意:这里的父类应该是项目中的基础业务异常类;

java 复制代码
public class TimeoutCheckException extends RuntimeException{

    public TimeoutCheckException(String message) {
        super(message);
    }

    public TimeoutCheckException(String message, Throwable throwable) {
        super(message, throwable);
    }
}

再顺便定义一个属性配置:

这个的作用是全局控制开关,当不需要的时候可以直接通过配置关闭;

java 复制代码
@Component
@ConfigurationProperties(prefix = "aliweb.timeout")
public class TimeoutCheckProperties {

    private boolean enable = true;

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}

最后就是我们的aop类:

java 复制代码
@Aspect
@Component
public class TimeoutAop {

    private static final Logger logger = LoggerFactory.getLogger(TimeoutAop.class);

    @Autowired
    private TimeoutCheckProperties timeoutCheckProperties;

    @Pointcut("@annotation(timeoutCheck)")
    public void pointCut(TimeoutCheck timeoutCheck) {
    }

    @Around(value = "pointCut(timeoutCheck)", argNames = "joinPoint, timeoutCheck")
    public Object around(ProceedingJoinPoint joinPoint, TimeoutCheck timeoutCheck) throws Throwable {
        if (!timeoutCheckProperties.isEnable()) {
            return joinPoint.proceed();
        }
        long timeout = timeoutCheck.timeout();
        if (timeout <= 0) {
            throw new TimeoutCheckException("业务逻辑执行时间不能小于等于0");
        }
        long start = System.currentTimeMillis();
        String msg = null;
        Exception error = null;
        Object data = null;
        FutureTask<Object> futureTask = createTask(joinPoint);
        try {
            Thread thread = new Thread(futureTask);
            thread.start();
            data = futureTask.get(timeout, timeoutCheck.unit());
        } catch (InterruptedException e) {
            msg = "执行中断";
            error = e;
        } catch (ExecutionException e) {
            msg = "执行异常";
            error = e;
        } catch (TimeoutException e) {
            msg = "执行超时";
            error = e;
        } finally {
            futureTask.cancel(timeoutCheck.destroy());
        }
        logger.debug("执行时间:{}", System.currentTimeMillis() - start);
        if (error != null) {
            String suf = error.getMessage() == null ? "" : ":" + error.getMessage();
            logger.error(msg + suf, error);
            throw new TimeoutCheckException(msg + suf, error);
        }
        return data;
    }

    private static FutureTask<Object> createTask(ProceedingJoinPoint joinPoint) {
        return new FutureTask<>(() -> {
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        });
    }

}

starter组件

将功能提取成starter组件:

  1. 定义配置类
java 复制代码
@Configuration
@ComponentScan("com.liry.aliweb.timeout")
public class TimeoutCheckAutoConfig {
}
  1. 定义配置扫描文件spring.factories,路径:

    src/main/resources/META-INF/spring.factories

    properties 复制代码
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.liry.aliweb.timeout.config.TimeoutCheckAutoConfig
  2. pom增加依赖:

    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>

如上,在主项目引入时就可以直接使用了

相关推荐
weixin_419658317 分钟前
Spring的三级缓存和SpringMVC的流程
java·spring·缓存
paopaokaka_luck16 分钟前
基于SpringBoot+Vue的DIY手工社预约管理系统(Echarts图形化、腾讯地图API)
java·vue.js·人工智能·spring boot·后端·echarts
自在极意功。17 分钟前
贪心算法深度解析:从理论到实战的完整指南
java·算法·ios·贪心算法
计算机学姐4 小时前
基于微信小程序的高校班务管理系统【2026最新】
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
一路向北⁢4 小时前
基于 Apache POI 5.2.5 构建高效 Excel 工具类:从零到生产级实践
java·apache·excel·apache poi·easy-excel·fast-excel
毕设源码-赖学姐7 小时前
【开题答辩全过程】以 基于Android的校园快递互助APP为例,包含答辩的问题和答案
java·eclipse
damo017 小时前
stripe 支付对接
java·stripe
麦麦鸡腿堡8 小时前
Java的单例设计模式-饿汉式
java·开发语言·设计模式
假客套8 小时前
Request method ‘POST‘ not supported,问题分析和解决
java
傻童:CPU8 小时前
C语言需要掌握的基础知识点之前缀和
java·c语言·算法