目录
1.基本概念
1.1.切面类 @Aspect
1.2.切点 @Pointcut
1.3.Advice
1.4.JoinPoint
1.5.运算符用法
1.6.@annotation(annotationType)
1.7.代理对象
1.8.调用切面注解
2.代码展示
写在前面:在开发过程中,需要对每个方法执行时进行日志记录、返回值的解析,简单整理一下有关AOP的相关知识点。
定义切面类,加上@Aspect、@Component注解;(下文有展示)
(1)指定切面方法
execution表达式
第一个*表示匹配任意的方法返回值,
..(两个点)表示零个或多个,
第一个..表示module包及其子包,
第二个*表示所有类,
第三个*表示所有方法,
第二个..表示方法的任意参数个数
//org.jeecg.modules.dlglong.controller;
//com.sd3e.projectmanager.controller.acceptanceApplication;
@Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..))||execution(public * com.*.projectmanager..*.*Controller.*(..))")
public void excudeService() {
}
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time1=System.currentTimeMillis();
Object result = pjp.proceed();
long time2=System.currentTimeMillis();
log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");
long start=System.currentTimeMillis();
this.parseDictText(result);
long end=System.currentTimeMillis();
log.debug("注入字典到JSON数据 耗时"+(end-start)+"ms");
return result;
}
@Pointcut("execution(public * com.rest.module..*.*(..))")
public void getMethods() {
}
(2)指定注解
在这里,自定义了一个注解类,方法加注解即可使用
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
public void pointCut() {
}
package org.jeecg.common.aspect.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据权限注解
* @Author taoyan
* @Date 2019年4月11日
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
public @interface PermissionData {
/**
* 暂时没用
* @return
*/
String value() default "";
/**
* 配置菜单的组件路径,用于数据权限
*/
String pageComponent() default "";
}
@Pointcut("@annotation(com.rest.utils.SysPlatLog)")
public void withAnnotationMethods() {
}
public @interface SysPlatLog {
// 操作名称
String operateName() default "";
// 操作描述
String logNote() default "";
}
在切入点上执行的增强处理,主要有五个注解:
@Before 在切点方法之前执行
@After 在切点方法之后执行
@AfterReturning 切点方法返回后执行
@AfterThrowing 切点方法抛异常执行
@Around 属于环绕增强,能控制切点执行前,执行后
方法中的参数JoinPoint为连接点对象,它可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息,验证一些信息等;
使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系;
1.2.代码中给出了示例
匹配指定注解为切入点的方法;
//aop代理对象
Object aThis = joinPoint.getThis();
//被代理对象
Object target = joinPoint.getTarget();
@AutoLog(value = "ws_xbx-分页列表查询")
@ApiOperation(value="ws_xbx-分页列表查询", notes="ws_xbx-分页列表查询")
@GetMapping(value = "/list")
@PermissionData(pageComponent="sd3e/actDemo/WsXbxList")//sys_permission 表组件路径 component 字段
public Result> queryPageList(WsXbx wsXbx,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(wsXbx, req.getParameterMap());
Page page = new Page(pageNo, pageSize);
IPage pageList = wsXbxService.page(page, queryWrapper);
return Result.OK(pageList);
}
@SysPlatLog(operateName = "查看详情",logNote = "查看详情")
@SneakyThrows
public Result getItem(@RequestParam(required = false) String bs){
}
package com.npc.rest.utils;
import com.npc.rest.common.properites.AppSupPlatProperties;
import com.sys.model.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.*;
@Aspect
@Slf4j
@Component
public class SysPlatLogAspect {
/**
* 指定切面
*/
@Pointcut("execution(public * com.rest.module..*.*(..))")
public void getMethods() {
}
/**
* 指定注解
*/
@Pointcut("@annotation(com.rest.utils.SysPlatLog)")
public void withAnnotationMethods() {
}
/***
* 拦截控制层的操作日志
* @param joinPoint
* @return
* @throws Throwable
*/
@After(value = "getMethods() && withAnnotationMethods()")
public void recordLog(JoinPoint joinPoint) throws Throwable {
SysLog sysLog = new SysLog();
SysPlatLog sysPlatLog = getInter(joinPoint);
sysLog.setOperateName(sysPlatLog.operateName());
sysLog.setLogNote(sysPlatLog.logNote());
sysLog.setLogTime(new Date());
sysLog.setAppCode(AppSupPlatProperties.getAppCode());
}
public SysPlatLog getInter(JoinPoint joinPoint) throws ClassNotFoundException {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
SysPlatLog sysPlatLog = method.getAnnotation(SysPlatLog.class);
return sysPlatLog;
}
}
}
return null;
}
}
多个切面执行顺序