AOP 总结
一、简介
工作中一定会用到aop,而博主主要应用场景也仅仅局限于日志的处理,久而久之仅仅停留在了日志应用上,不免有点照本宣科,所以花了点时间进行了总结,本篇文章主要是针对aop的概念的阐述以及相关应用的实现。
二、AOP原理
说到AOP(面向切面)一定会想到OOP(面向对象编程),面向对象则是将一个个class(对象)作为基本单元,那同理面向切面则将一个个切面作为我们的单元体;
在我们传统的自上而下的逻辑代码开发中不免会出现很多重复冗余的非核心业务逻辑代码,比如说请求的参数和响应体的日志,异常捕捉,报警信息等,这时候需要一个切面来将其抽离出来,成为一个类似公共的方法,但这公共部分(切面)并不是由业务代码去调用,而是切面主动去切入到业务中进行捕捉,所以aop更明确的说是一种设计思想,达到了代码的解耦目的。
三、AOP核心概念(关键词)
- aspect:横切关注点的抽象,可以认为加了@Aspect 注解的类就是切面
@Slf4j
@Aspect
@Component
public class AccessLogAspect {}
- Pointcut 切入点,注明切入的位置
标注为我们切面的切入点为整个controller
@Pointcut(value = "execution(* com.fellix.gateway.controller.app.*Controller.*(..))")
public void allMethods() {
}
- joinpoint 连接点,具体值我们切入位置中的方法
@Around("allMethods()")
public Object around(ProceedingJoinPoint point) throws Throwable {}
- advice 通知,主要分为前置,后置,异常,环绕,最终这五类
- 前置:@Before 在joinpoint前执行
- 后置:@After 在joinpoint返回后执行,无论joinpoint是否正常推出还是异常退出
- 异常:@AfterThrowing 在joinpoint抛出异常后执行
- 环绕:@Around 无论joinpoint前还是后都会执行
- 最终:@AfterReturning joinpoint正常退出后执行
- aop target:aop的代理对象,aop通过动态代理实现aspect,JoinPoint 是目标对象的代理对象
四、实践应用
/**
* @Author: Felix
* @Date: 2021/2/26 3:53 下午
* @Description: 打印数据库链接信息,BaseResponse (封装的公共响应体,需要自己构建)
**/
@Component
@Aspect
@Order(1)
@Slf4j
public class AccessLogAop {
@Resource(name = "dataSource")
DruidDataSource defaultDataSource;
@Pointcut(value = "execution(* com.balabala..*Controller.*(..))")
public void allMethods() {
}
@Around("allMethods()")
public Object around(ProceedingJoinPoint point) throws Throwable {
int size = defaultDataSource.getActiveConnections().size();
long connectCount = defaultDataSource.getConnectCount();
long createCount = defaultDataSource.getCreateCount();
long commitCount = defaultDataSource.getCommitCount();
int waitThreadCount = defaultDataSource.getWaitThreadCount();
long connectErrorCount = defaultDataSource.getConnectErrorCount();
log.info("打印数据库连接信息,当前活跃连接数:{},创建数:{},连接数:{},提交数:{},等待线程数:{},连接错误数:{}",size,createCount,connectCount,commitCount,waitThreadCount,connectErrorCount);
BaseResponse apiResponse = null;
try {
Object proceed = point.proceed();
if (proceed instanceof BaseResponse) {
apiResponse = (BaseResponse) proceed;
return apiResponse;
}
return proceed;
} catch (Throwable e) {
Exception ex = (Exception) e;
log.error("app request error", ex);
throw e;
} finally {
log.info("数据库打印信息aop结束");
}
}
}