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>

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

相关推荐
A尘埃1 小时前
智慧零售全渠道业务中台系统
java·零售
小wanga5 小时前
C++知识
java·开发语言·c++
我是渣哥5 小时前
Java String vs StringBuilder vs StringBuffer:一个性能优化的探险故事
java·开发语言·jvm·后端·算法·职场和发展·性能优化
工一木子5 小时前
深入Java并发:锁机制原理剖析与性能优化实战
java·性能优化·并发·
你我约定有三5 小时前
java--写在 try 中的创建连接
java·开发语言
ERP老兵-冷溪虎山5 小时前
Python/JS/Go/Java同步学习(第三篇)四语言“切片“对照表: 财务“小南“纸切片术切凭证到崩溃(附源码/截图/参数表/避坑指南/老板沉默术)
java·javascript·python·golang·中医编程·四语言同步学习·职场生存指南
科技树支点5 小时前
无GC的Java创新设计思路:作用域引用式自动内存管理
java·python·go·web·编程语言·编译器
码农小伙5 小时前
ConcurrentHashMap解析
java·开发语言
WhiteJunior5 小时前
Java基础知识点汇总(五)
java·开发语言