spring 详解
根据上一篇 aop 的介绍,这篇通过spring的注解更详细的介绍aop的使用场景
spring 注解
注解最有特色的标记就是 @interface 了
@Documented //说明该注解将被包含在javadoc中
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
@Target
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention
- SOURCE:在源文件中有效,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中
- CLASS:在class文件中有效m,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候
- RUNTIME:在运行时有效,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时
@Inherited
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
我们要实现的功能是,检测该接口请请求到结束,花了多少时间
在接口上添加该注解。
@Log("查询所有日志")
@RequestMapping("queryAll")
public String queryAll(HadesCurrencyLog hadesCurrencyLog,String beginTime,String endTime){
return currencyLogService.queryAll(hadesCurrencyLog,beginTime,endTime);
}
用@Around 注解
具体实现
@Slf4j
@Aspect
@Component
public class LogAspect {
@Pointcut("@annotation(com.longchuang.common.annotation.Log)")
public void pointcut() {
// do nothing
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = null;
long beginTime = System.currentTimeMillis();
// 执行方法
result = point.proceed();
// 获取 request
HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
// 设置 IP 地址
String ip = IPUtil.getIpAddr(request);
// 执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
if (sixsectorProperties.isOpenAopLog()) {
// 保存日志
String token = (String) SecurityUtils.getSubject().getPrincipal();
String username = "";
if (StringUtils.isNotBlank(token)) {
username = JWTUtil.getUsername(token);
}
SysLog log = new SysLog();
log.setUsername(username);
log.setIp(ip);
log.setTime(time);
logService.saveLog(point, log);
}
return result;
}
}
详解一下 ProceedingJoinPoint 对象
首先 @Around 注解,包含着before 和 after 的行为
result = point.proceed() 方法执行划分before 和 after ,执行则说明方法已经走完(注意:point.proceed() 方法一定要执行)