文章目录
简介
应用场景
日志
- 日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此。
事务
- 调用方法前开启事务, 调用方法后提交关闭事务
术语
切点
连接点
JDK代理
CGLIB代理
Spring 5 代理
代理机制
- 默认是JDK代理,因为是建议多用接口来设计程序
- 也可以强制使用CGLIB代理
Springboot
Springboot 2.x 代理
- Spring 5.x中AOP默认依旧使用JDK动态代理
- SpringBoot 2.x开始,为了解决使用JDK动态代理可能导致的类型转换异常,而使用CGLIB。
- 在SpringBoot 2.x中,如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。
Springboot Aop 例子
@Aspect
@Component
public class FaultEventAnalyzeAspect {
private static Logger log = LoggerFactory.getLogger(FaultEventAnalyzeAspectTest.class);
@Autowired
FaultEventUtil faultEventUtil;
/**
* @Description: analyseEvents为前缀的方法
* @Param:
* @return:
*/
@Pointcut("execution(public * com.dfe.e8800p.scheduler.service.impl.*.analyze(..))")
public void excutePoint() {
log.info("analyse方法 为切点");
}
// // 前置通知:在目标方法执行之前执行
// @Before(value = "excutePoint()")
// public void befor(JoinPoint joinPoint) {
// String name = joinPoint.getSignature().getName();
// System.out.println(name + "方法, 执行 befor");
// }
//
// // 后置通知:在目标方法执行之后执行
// @After(value = "excutePoint()")
// public void after(JoinPoint joinPoint) {
// String name = joinPoint.getSignature().getName();
// System.out.println(name + "方法, 执行 after");
// }
//
// // 返回通知:获取目标方法的返回值
// @AfterReturning(value = "excutePoint()", returning = "result")
// public void afterReturning(JoinPoint joinPoint, Object result) {
// String name = joinPoint.getSignature().getName();
// System.out.println(name + "方法, 执行 " + "afterReturning" + ", 返回: " + result);
// }
//
// // 异常通知:当目标方法出现异常时,会执行该方法
// @AfterThrowing(value = "excutePoint()", throwing = "e")
// public void afterThrowing(JoinPoint joinPoint, Exception e) {
// String name = joinPoint.getSignature().getName();
// System.out.println(name + "方法, 执行 " + "afterThrowing" + ", 抛出异常: " + e);
// }
//
// 环绕通知:可实现任意通知,可调用 proceedingJoinPoint.proceed() 方法使目标方法继续执行
/**
* @Description: 分析事件之前打印日志,统计耗时
* @Param:
* @return:
*/
@Around(value = "excutePoint()")
public Object around(ProceedingJoinPoint proceedingJoinPoint){
Date start = new Date();
String[] nameArr = proceedingJoinPoint.getSignature().getDeclaringTypeName().split("\\.");
String name=nameArr[nameArr.length-1];
log.info(name + " start");
/*执行方法*/
Object object = null;
try {
object=proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
/*分析结果保存到数据库*/
faultEventUtil.insertEventsList();
log.info(name + " finished,cost " + DateUtil.between(start, new Date(), DateUnit.SECOND) + " s");
return object;
}
}
常用的AOP通知类型
参考链接
Aspect Oriented Programming with Spring
SpringBoot AOP的使用
SpringBoot在2.x默认使用Cglib动态代理
SpringBoot - 面向切面编程 AOP 的配置和使用(附样例)
Spring AOP切点表达式