Spring支持切面编程的特性。一般可用于通用的预处理、尾处理、日志记录、信息统计等用途。
这里针对耗时统计做一个切面:
1.切面代码
需要注意这里的@Around多种环绕搜索方式
- @within(LogCostTime) : 匹配注解了LogCostTime的方法
- @annotation(LogCostTime) : 匹配注解了LogCostTime的类(其所有方法被环绕)
- within(intf.CostTimeLogable+) :匹配实现了CostTimeLogable的类(后面的符号“+”表示包括子类)
@Slf4j
@Component
@Aspect
public class LogCostTimeAspect {
@Value("${enableLogCostTime:true}")
private boolean enableLogCostTime;
@Value("${logArgs:false}")
private boolean logArgs;
@Around("@within(LogCostTime) || @annotation(LogCostTime) || within(intf.CostTimeLogable+)")
public Object aroundLogCostTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
if (enableLogCostTime) {
long start = System.currentTimeMillis();
try {
return proceedingJoinPoint.proceed();
} finally {
long costTime = System.currentTimeMillis() - start;
String className = proceedingJoinPoint.getSignature().getDeclaringType().getSimpleName();
String methodName = proceedingJoinPoint.getSignature().getName();
if (logArgs) {
log.info("execute the method '{}.{}' cost {} milliseconds , args are : \n{} "
, className, methodName, costTime, Arrays.toString(proceedingJoinPoint.getArgs()));
} else {
log.info("execute the method '{}.{}' cost {} milliseconds", className, methodName, costTime);
}
}
} else {
return proceedingJoinPoint.proceed();
}
}
}
public interface CostTimeLogable {
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogCostTime {
}
2.使用方法
1.通过注解bean的方法
bean的方法定义上打上LogCostTime注解,对应bean的方法,以bean的引用方式被外部调用时,会走切面调用。
@Slf4j
@Service
public class Test1{
@LogCostTime
int test();
}
2.通过注解bean的类
bean的类定义上打上LogCostTime注解,所有bean的方法,以bean的引用方式被外部调用时,会走切面调用。
@Slf4j
@Service
@LogCostTime
public class Test1{
int test();
}
3.通过实现指定接口。
实现CostTimeLogable 的所有实例bean在以bean的引用方式被外部调用方法时,会打印耗时信息。
此场景主要应用在无法直接定义spring bean的情况下,如mybatis的DAO访问,业务上只需定义DAO
接口,实例是通过动态代理生成的子类,这种情况下对DAO接口直接打注解是无法进行切面的。使用这种方式,由于接口是多层继承的,DAO的子类也能够切面调用。
public interface testDao extends CostTimeLogable {
int test();
}
网友评论