一.引入.
最近在使用Hystrix降级组件的时候,好奇它是怎样通过注解实现降级,于是思考后用自己的方式实现超时降级的功能(目前还没有看Hystrix源码,并不一定和其内部实现相同).
二.大体实现思路.
- 定义注解,给定执行时间和降级方法
- 使用aop监控对应方法执行,对方法进行拦截.
- 利用Future对方法执行时间控制,超出指定时间抛出超时异常
- 捕获异常,执行降级方法
三.具体实现.
1.工程目录结构
2.启动类
AopAnnotionApplication
@SpringBootApplication
@EnableAspectJAutoProxy
public class AopAnnotionApplication {
public static void main(String[] args) {
SpringApplication.run(AopAnnotionApplication.class, args);
}
}
MyApplicationRunner
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Resource
private AnnotationTest annotationTest;
@Override
public void run(ApplicationArguments args) throws Exception {
annotationTest.annotionTest();
annotationTest.noAnnotion();
}
}
3.业务类.
Myannotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Myannotation {
int executionTime() default 1;
String fallbackMethodName();
}
AnnotationTest
@Component
public class AnnotationTest {
@Myannotation(executionTime=3,fallbackMethodName = "fallbackMethod")
public void annotionTest(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void fallbackMethod(){
System.out.println("已执行降级方法");
}
public String noAnnotion(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Thread.currentThread().getName();
}
}
AnnotaionAspect
@Component
@Aspect
public class AnnotaionAspect {
static ExecutorService threadPool= Executors.newFixedThreadPool(2);
@Pointcut("execution(* com.example.aopannotion.service.*.*(..))")
public void pt(){}
@Around("pt()")
public void aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint){
//获取类对象
Object targetObject = proceedingJoinPoint.getTarget();
//获取方法名称
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
try {
//通过反射获取方法上是否有注解
Method method = targetObject.getClass().getMethod(signature.getName(), signature.getParameterTypes());
Myannotation annotation = method.getAnnotation(Myannotation.class);
//没有注解不进行时间统计,直接执行方法
if(annotation == null){
System.out.println(signature.getName() + "方法无注解,无需检测执行时间.");
proceedingJoinPoint.proceed();
}
//有注解,检测执行时间是否大于指定时间
else{
System.out.println(signature.getName() + "方法检测到注解,开始检测执行时间.");
int specifyExTime = annotation.executionTime();
String methodName = annotation.fallbackMethodName();
//使用单独线程执行对应方法,并监控执行时间
try{
executeSpecialMethod(proceedingJoinPoint,specifyExTime);
System.out.println(signature.getName() + "方法执行完毕,未超过指定时间:"+specifyExTime+"s");
}catch (TimeoutException e){
//调用方法超时,执行降级方法
System.out.println(signature.getName() + "方法执行时间超过指定时间:"+specifyExTime+"s,开始执行降级方法");
Method fallbackMethod = targetObject.getClass().getMethod(methodName);
fallbackMethod.invoke(targetObject,fallbackMethod.getParameterTypes());
}catch (Exception e){
throw e;
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
/**
* 执行指定方法并监控执行时间,如果在指定时间内没有执行完毕,则直接抛出异常
* @param proceedingJoinPoint
* @param specifyExTime
* @return
*/
private void executeSpecialMethod(ProceedingJoinPoint proceedingJoinPoint, int specifyExTime) throws InterruptedException, ExecutionException, TimeoutException {
Callable<Object> callable = new Callable<Object>() {
@Override
public Object call() throws Exception {
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return "success";
}
};
Future<Object> future = threadPool.submit(callable);
future.get(specifyExTime, TimeUnit.SECONDS);
}
}
四.代码执行效果.