AOP 原理:
第一.将复杂的需求分解出不同的方面,将公共功能集中解决。
第二、采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能
所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态添加功能的技术
AOP:
面向切面编程,相对于OOP切面编程
Spring 的AOP为了解耦,AOP可以让一组类共享相同的行为
Spring 支持Aspect声明的注解式切面编程
下面的代码示例:
为了解决在执行某个方法时,需要切换数据库
@Aspect
@Component
public class DataSourceAspect {
@Before("execution(* cn.com.citydo.web.mapper.oracle.ExecuteSqlFromOracleMapper.execute(..))")
public void setSecondaryDataSource(JoinPoint point) {
DatabaseContextHolder.setDatabaseType(DatabaseType.secondaryDb);
}
@After("execution(* cn.com.citydo.web.mapper.oracle.ExecuteSqlFromOracleMapper.execute(..))")
public void setPrimaryDataSource(JoinPoint point) {
DatabaseContextHolder.setDatabaseType(DatabaseType.primaryDb);
}
}
最常见的切面日志配置
package cn.com.citydo.datawindow.config;
import cn.com.citydo.datawindow.dto.base.BaseResponse;
import cn.com.citydo.datawindow.util.annotation.log.LogAnnotation;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* 切面日志配置
*
* @author yss
*/
@Slf4j
@Aspect
@Component
public class ControllerAspect {
/**
* 切面环绕写入方法名
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("@annotation(logAnnotation)")
public Object interceptor(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) throws Throwable {
long start = System.currentTimeMillis();
// 类路径
String className = joinPoint.getSignature().getDeclaringTypeName();
// 方法名
String methodName = joinPoint.getSignature().getName();
StringBuilder sb = new StringBuilder();
sb.append(className).append(".").append(methodName);
log.info("开始调用方法:{}", sb);
log.info("请求参数 : " + JSON.toJSON(joinPoint.getArgs()));
// 后置通知获取返回结果集,proceed()方法只可调一次,否则会重复执行业务服务
Object responseObj = joinPoint.proceed();
// 计算服务端接口耗时,单位毫秒
long costTime = System.currentTimeMillis() - start;
// 响应结果为BaseResponse时添加方法名
BaseResponse response;
if (responseObj instanceof BaseResponse) {
response = (BaseResponse) responseObj;
response.setAction(methodName);
response.setCostTime(costTime);
} else {
return responseObj;
}
// 后置通知记录返回对象
log.info("结束调用方法:{}, 耗时:{}ms", sb, costTime);
log.info("调用结果 : " + JSON.toJSON(responseObj));
// 结束切面
return response;
}
}
1) @Aspect 声明一个切面
2) @Component 让此切面成为spring 容器管理的bean
3) @PointCut 注解声明切点