<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
package com.per.aop;
import java.lang.annotation.*;
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Timeout {
long time() default 3000L;
Class clazz() default Object.class;
}
package com.per.aop;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
@Aspect
@Slf4j
@Component
public class TimeoutAspect {
public static final ThreadPoolExecutor TIMEOUT_POOL = new ThreadPoolExecutor(2, 128,
60L, TimeUnit.SECONDS, new SynchronousQueue<>(),
new ThreadFactoryBuilder().setNameFormat("TimeoutAspect-pool-%d").build());
@Pointcut(value = "@annotation(com.per.aop.Timeout)")
public void pointCut() {
}
@Around(value = "pointCut()")
public Object timeOut(ProceedingJoinPoint joinPoint) throws InterruptedException {
log.info("timeout aop enter...");
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
Timeout timeOut = method.getDeclaredAnnotation(Timeout.class);
Class returnClazz = Object.class.equals(timeOut.clazz()) ? method.getReturnType() : timeOut.clazz();
Future future = TIMEOUT_POOL.submit(() -> {
log.info("timeout aop method start...");
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
return getDefaultValue(returnClazz);
}
});
try {
return future.get(timeOut.time(), TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
future.cancel(true);
log.error("timeout aop method timeout:{}", timeOut.time());
return getDefaultValue(returnClazz);
}
}
private static Object getDefaultValue(Class clazz) {
if (clazz == null || Object.class.equals(clazz)) {
return null;
} else if (String.class.equals(clazz)) {
return "";
} else if (ArrayList.class.equals(clazz) || List.class.equals(clazz)) {
return new ArrayList<>(0);
} else if (HashMap.class.equals(clazz) || Map.class.equals(clazz)) {
return new HashMap<>(0);
}
try {
Constructor constructor = clazz.getConstructor();
return constructor.newInstance();
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
log.error("There is no non-parameter constructor, return null, class:{}", clazz);
return null;
} catch (Exception e) {
log.error("return default value error", e);
return null;
}
}
}
@Timeout(time = 5000L)
public String getToken() {
}