/**
* @Description TODO
* 
* @Date 2021/2/28 23:07
* @Created by moyun
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName(“com_sys_log”)
public class SysLog implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = “id”, type = IdType.AUTO)
private Long id;
private String className;
private String methodName;
private String params;
private Long excTime;
private String remark;
private String createDate;
}

「定义日志切面」

/**
* @Description TODO
* 
* @Date 2021/2/28 23:19
* @Created by moyun
*/
@Aspect //使用@Aspect
@Component
public class SysLogAsp {
@Autowired
private SysLogService sysLogService;
/**
*定义切点, 这里我们使用注解的形式
* 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
* 切点表达式:   execution(…)
*/
@Pointcut(“@annotation(com.kjyfx.annotation.SysLog)”)
public void logPointCut() {}
/**
* 添加环绕通知@Around
* @param point
* @return
* @throws Throwable
*/
@Around(“logPointCut()”)
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - beginTime;
try {
//实现保存日志逻辑
saveLog(point, time);
} catch (Exception e) {
}
return result;
}
/**
* 保存日志
* @param joinPoint
* @param time
*/
private void saveLog(ProceedingJoinPoint joinPoint, long time) {
// 获取方法的关键信息,类,包
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogEntity sysLogEntity = new SysLogEntity();
sysLogEntity.setExcTime(time);
SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd hh:mm:ss”);
sysLogEntity.setCreateDate(dateFormat.format(new Date()));
SysLog sysLog = method.getAnnotation(SysLog.class);
if(sysLog != null) {
//注解上的描述
sysLogEntity.setRemark(sysLog.value());
}
//请求的 类名、方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLogEntity.setClassName(className);
sysLogEntity.setMethodName(methodName);
//请求的参数
Object[] args = joinPoint.getArgs();
try {
List list = new ArrayList();
for (Object o : args) {
list.add(o.toString());
}
sysLogEntity.setParams(list.toString());
} catch (Exception e){
}
sysLogService.save(sysLogEntity);
}
}

控制类添方法上添加@SysLog注解

/**
* @Description TODO
*
* @Date 2021/2/28 23:07
* @Created by moyun
*/
@RestController
@RequestMapping(“/sysUser”)
public class SysUserController {
@Autowired
private SysUserService userService;
@RequestMapping(“/getUserById/{id}”)
@SysLog(“根据Id获取用户”)
public BaseResponse getUserById(@PathVariable Long id){
SysUser user = userService.getById(id);
return BaseResponse.renderSuccess(“成功!”,user);
}
}

通过postman访问本地接口,成功获取到数据

springboot aop切面异步_Java

此时查看数据库系统日志表,则会看到对应的日志信息

springboot aop切面异步_spring boot_02

切入点表达式


定义切入点的时候需要一个包含名字和任意参数的签名,还有一个切入点表达式,如execution(public * com.example.aop…(…))

切入点表达式的格式:execution([可见性]返回类型[声明类型].方法名(参数)[异常])

其中[]内的是可选的,其它的还支持通配符的使用:

*:匹配所有字符

…:一般用于匹配多个包,多个参数

+:表示类及其子类

运算符有:&&,||,!

「切入点表达式关键词用例」

execution:用于匹配子表达式。//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意 @Pointcut(“execution(* com.cjm.model…(…))”) public void before(){}

within:用于匹配连接点所在的Java类或者包。//匹配Person类中的所有方法 @Pointcut(“within(com.cjm.model.Person)”) public void before(){} //匹配com.cjm包及其子包中所有类中的所有方法 @Pointcut(“within(com.cjm…*)”) public void before(){}

this:用于向通知方法中传入代理对象的引用。@Before(“before() && this(proxy)”) public void beforeAdvide(JoinPoint point, Object proxy){ //处理逻辑 }

target:用于向通知方法中传入目标对象的引用。@Before(“before() && target(target) public void beforeAdvide(JoinPoint point, Object proxy){ //处理逻辑 }

args:用于将参数传入到通知方法中。@Before(“before() && args(age,username)”) public void beforeAdvide(JoinPoint point, int age, String username){ //处理逻辑 }

@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。@Pointcut(“@within(com.cjm.annotation.AdviceAnnotation)”) - 所有被@AdviceAnnotation标注的类都将匹配 public void before(){}