文章目录
- 前言
- 1.环境搭建
- 2.设计日志记录表
- 3.aop需要引入aspectj依赖
- 4.日志实体类设计
- 5.自定义日志BusiLog注解
- 6.定义日志切面
- 6.1 此处只使用了环绕通知
- 6.2 @Aspect中有5种通知
- 7.业务中使用注解
- 8.测试
- 8.1 测试查询
- 8.2 测试删除
前言
上篇分享了jdk动态代理以及cglib代理,是对某个接口或者类进行增强扩展实现。AOP (Aspect Orient Programming),面向切面编程,AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,实现开闭原则。下边我们以实现aop实现日志的记录为例。
1.环境搭建
jdk1.8+IDEA+MyBatisPlus+mysql实现。
具体的安装不在这里赘述。
2.设计日志记录表
CREATE TABLE `busi_log` (
`ID` bigint(20) NOT NULL COMMENT '主键id',
`USER_ID` bigint(20) DEFAULT NULL COMMENT '用户id',
`CLASS_NAME` varchar(255) DEFAULT NULL COMMENT '类名称',
`METHOD` varchar(100) DEFAULT NULL COMMENT '方法名称',
`DESCRIPTION` text COMMENT '方法描述',
`CREATE_DATE` datetime DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`ID`) USING BTREE,
KEY `ID` (`ID`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作日志表';
3.aop需要引入aspectj依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
4.日志实体类设计
/**
* 操作日志表
*/
@TableName("busi_log")
public class BusiLog {
//主键id
@TableId(value = "ID", type = IdType.ASSIGN_ID)
protected Long id;
//用户id
@TableField(value = "USER_ID")
protected Long userId;
//类名称
@TableField(value = "CLASS_NAME")
protected String className;
//方法名称
@TableField(value = "METHOD")
protected String method;
//方法描述
@TableField(value = "DESCRIPTION")
protected String description;
// 创建日期
@TableField(value = "CREATE_DATE", fill = FieldFill.INSERT)
protected Date createDate;
//此处省略 set get方法
}
5.自定义日志BusiLog注解
/**
* 自定义日志注解
*/
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BusiLog {
/**
* 操作具体某个功能的描述
* @return
*/
String desc() default "";
}
6.定义日志切面
6.1 此处只使用了环绕通知
实际业务中我们还可能记录异常日志,操作日志,等等。
/**
* 日志切面类
*/
@Component
@Aspect
@Slf4j
public class BusiLogAop {
/**
* 引入日志持久化的mapper类
*/
@Autowired
private BusiLogMapper busiLogMapper;
/**
* 定义BusLogAop的切入点为标记@BusLog注解的方法
*/
@Pointcut(value = "@annotation(com.elite.mybatisplus.annotation.BusiLog)")
public void pointcut() {
}
/**
* 业务操作环绕通知
*
* @param proceedingJoinPoint
* @retur
*/
@Around("pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) {
log.info("==========BusiLogAop环绕通知===============");
//执行目标方法
Object result = null;
try {
result = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//目标方法执行完成后,获取目标类、目标方法上的业务日志注解上的功能名称和功能描述
Object target = proceedingJoinPoint.getTarget();
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
BusiLog anno = signature.getMethod().getAnnotation(BusiLog.class);
//没设计好名字,注解和实体类名字一致了
com.elite.mybatisplus.entity.BusiLog busiLogEntity = new com.elite.mybatisplus.entity.BusiLog();
busiLogEntity.setUserId(1L); //此处写死
busiLogEntity.setClassName(target.getClass().getName());
busiLogEntity.setMethod(signature.getMethod().getName());
busiLogEntity.setDescription(anno.desc());
busiLogEntity.setCreateDate(new Date());
//保存业务操作日志信息
this.busiLogMapper.insert(busiLogEntity);
log.info("----BusAop 环绕通知 end");
return result;
}
}
6.2 @Aspect中有5种通知
- @Before:前置通知, 在方法执行之前执行
- @Aroud:环绕通知, 围绕着方法执行
- @After:后置通知, 在方法执行之后执行
- @AfterReturning:返回通知, 在方法返回结果之后执行
- @AfterThrowing:异常通知, 在方法抛出异常之后
7.业务中使用注解
直接在方法上边使用注解即可。
/**
* 人员信息管理
*/
@RestController
public class PersonController {
@Autowired
IPersonService personService;
/**
* 查询人员信息列表
* @return
*/
@BusiLog(desc = "查询人员信息列表")
@GetMapping("/getPersonList")
public List<Person> getPersonList(){
return personService.list();
}
/**
* 新增人员信息
*/
@BusiLog(desc = "新增人员信息")
@PostMapping("/addPerson")
public String addPerson(@RequestBody Person person){
personService.save(person);
return "新增人员信息成功!";
}
/**
* 更新人员信息
*/
@BusiLog(desc = "更新人员信息")
@PostMapping("/updatePerson")
public String updatePerson(@RequestBody Person person){
personService.updateById(person);
return "更新人员信息成功!";
}
/**
* 删除人员信息
*/
@BusiLog(desc = "删除人员信息")
@GetMapping("/deletePersonById/{id}")
public String deletePersonById(@PathVariable("id")Long id){
personService.removeById(id);
return "删除成功!";
}
}
8.测试
此处我们只测试查询,看看效果。
8.1 测试查询
8.2 测试删除
新增和修改就不测试,同样的方法。