写在前面:借助springboot aop写了一个Logtodo注解,用于输出程序中打了该注解的类及其对应的方法名称,以及所标注的注解的内容。写该注解的目的是为了防止在程序编写过程中由于代码量太多,过程中会打很多todo,导致最后可能被遗忘。(然而,idea中有提供了TODO功能可以查看,不过无所谓了,就当练习一下自定义注解的编写方式了)
1、LogTodos文件
这部分是为了后续做重复注解使用
package com.alibaba.counsel.aitrain.service.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogTodos {
LOGTODO[] value();
}
2、LOGTODO注解
package com.alibaba.counsel.aitrain.service.aspect;
import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(LogTodos.class)
public @interface LOGTODO {
String[] message();
}
3、 定义Aspect函数
package com.alibaba.counsel.aitrain.service.aspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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.assertj.core.util.Lists;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Aspect
@Component
@Slf4j
public class TodoAspect {
/**
* 自定义切点
*
* 第一个"..":表示任意包
* 第二个"*":表示任意方法,..表示匹配任意参数
*/
static final String pointCutStr = "execution(* com.alibaba.counsel.aitrain.service.console..*(..))";
@Pointcut(value = pointCutStr)
public void todoShow(){
}
/**
* AOP:环绕通知
* 切整个包下面的所有涉及到调用方法的信息
* @param joinPoint
* @return
*/
@Around("todoShow()")
public Object doAround(ProceedingJoinPoint joinPoint){
Object obj = null;
try {
obj = joinPoint.proceed();
Class declaringType = joinPoint.getSignature().getDeclaringType();
log.info(declaringType.toString());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
LOGTODO[] annotationsByType = signature.getMethod().getAnnotationsByType(LOGTODO.class);
List<String[]> collect = Arrays.stream(annotationsByType).map(anno -> anno.message()).collect(Collectors.toList());
ArrayList<String> messages = new ArrayList<>();
for(String[] tmp:collect){
messages.addAll(Arrays.stream(tmp).collect(Collectors.toList()));
}
//获取类/接口 全路径名称
String targetClassName = joinPoint.getSignature().getDeclaringTypeName();
//获取类/接口 简洁路径名称
//String simpleName = joinPoint.getSignature().getDeclaringType().getSimpleName();
//获取方法名称
String methodName = joinPoint.getSignature().getName();
log.info("\033[0;93m类:[{}],方法:[{}],TODO:{}\033[0m",targetClassName,methodName,messages.toString());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}
}
参考资料
重复注解
使用Springboot 自定义注解完成 统计函数耗时功能
SpringBoot+AOP+统计单次请求方法的执行次数和耗时情况