AOP 面向切面编程
大约 4 分钟
AOP 面向切面编程
在此 AOP 面向切面编程 文章介绍了什么是面向切面编程,并介绍了如何使用注解的方式去实现切面。下面将介绍另一种实现切面编程, 这种方式虽然没有直接使用注解的方式方便,但是它足够灵活。
这里主要涉及到三个抽象类,分别是 AbstractBeanFactoryPointcutAdvisor
、MethodInterceptor
、StaticMethodMatcherPointcut
。
下面我们通过该方式来实现方法调用日志。
继承 StaticMethodMatcherPointcut
继承 StaticMethodMatcherPointcut 并重写什么 matches,通过重写该方法来实现咱们的切点,该方法就是用来识别切面何时生效。
@Slf4j
public class LogPointcut extends StaticMethodMatcherPointcut {
@Override
public boolean matches(Method method, @Nonnull Class<?> targetClass) {
Log annotation = method.getAnnotation(Log.class);
// 解析 这个 method 上有没有 @LogRecordAnnotation 注解,有的话会解析出来注解上的各个参数
return !Objects.isNull(annotation);
}
}
继承 BeanFactoryLogAdvisor
继承 BeanFactoryLogAdvisor 用于构建我们的切点实例。
public class BeanFactoryLogAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nonnull
@Override
public Pointcut getPointcut() {
return new LogPointcut();
}
}
继承 MethodInterceptor
继承 MethodInterceptor 重写 invoke 方法实现具体的切面。
@Slf4j
public class LogInterceptor implements MethodInterceptor {
private final IOperatorGetService operatorGetService;
private final ILogRecordService logRecordService;
private final IFunctionService functionService;
private final LogRecordExpressionEvaluator evaluator = new LogRecordExpressionEvaluator();
public LogInterceptor(IOperatorGetService operatorGetService, ILogRecordService logRecordService, IFunctionService functionService) {
this.operatorGetService = operatorGetService;
this.logRecordService = logRecordService;
this.functionService = functionService;
}
@Override
public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
return execute(invocation);
}
private Object execute(MethodInvocation invoker) throws Throwable {
Object target = invoker.getThis();
Method method = invoker.getMethod();
Object[] args = invoker.getArguments();
// 初始化上下文
LogRecordContext.init();
Throwable throwable = null;
// 获取注解
Log l = method.getAnnotation(Log.class);
// 表达式在评估上下文中执行。正是在这种情况下,在表达式评估期间遇到引用时会解析。
Class<?> targetClass = target.getClass();
EvaluationContext evaluationContext = evaluator.createEvaluationContext(target, method, targetClass, args);
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
Object res = null;
try {
// 处理
String description = l.success();
Map<String, String> functionMap = this.parseFunction(description);
// 执行需要预处理的函数
Map<String, String> map = this.handleFunction(functionMap, evaluationContext, methodKey, false);
// 执行代理方法
res = invoker.proceed();
evaluationContext.setVariable("_ret", res);
// 处理自定义函数
map.putAll(this.handleFunction(functionMap, evaluationContext, methodKey, true));
// 处理一般参数
map.putAll(this.paramCondition(description, evaluationContext, methodKey));
// 解析日志描述
String logDescription = this.parseLogDescription(description, map);
// 解析内容
OperationLog operationLog = operationLog(target, method, args)
.setDescription(logDescription)
.setOperationStatus(OperationStatus.SUCCESS)
.setOperation(l.operation())
.setResult(JSONUtil.toJsonStr(res));
logRecordService.record(operationLog);
} catch (Exception e) {
throwable = e;
String description = l.error();
evaluationContext.setVariable("_errorMsg", e.getMessage());
Map<String, String> functionMap = this.parseFunction(description);
// 处理自定义函数
Map<String, String> map = this.handleFunction(functionMap, evaluationContext, methodKey, true);
// 处理一般参数
map.putAll(this.paramCondition(description, evaluationContext, methodKey));
// 解析日志描述
String logDescription = this.parseLogDescription(description, map);
// 解析内容
OperationLog operationLog = operationLog(target, method, args)
.setDescription(logDescription)
.setOperationStatus(OperationStatus.ERROR)
.setOperation(l.operation())
.setThrowable(ExceptionUtil.stacktraceToString(e));
logRecordService.record(operationLog);
} finally {
// 清理上下文
LogRecordContext.clear();
}
// 将异常重新抛出去
if (Objects.nonNull(throwable)) {
throw throwable;
}
return res;
}
private Map<String, String> handleFunction(Map<String, String> functionMap, EvaluationContext evaluationContext, AnnotatedElementKey methodKey, boolean isAfter) {
Map<String, String> map = new HashMap<>();
for (Map.Entry<String, String> entry : functionMap.entrySet()) {
String function = entry.getKey();
String functionName = function.substring(1, function.indexOf("("));
if (isAfter || functionService.beforeFunction(functionName)) {
String value = entry.getValue();
Object r = StringUtils.isEmpty(value) ? null : evaluator.condition(value, methodKey, evaluationContext);
Object res = functionService.apply(functionName, r);
functionMap.remove(function);
map.put(function, this.toJson(res));
}
}
return map;
}
/**
* 解析自定义函数
*
* @param description 日志描述
* @return 函数map
*/
private Map<String, String> parseFunction(String description) {
// 函数执行
Map<String, String> map = new HashMap<>();
List<String> parseFunction = SpelUtils.parseFunction(description);
for (String function : parseFunction) {
List<String> list = new ArrayList<>();
String params = function.substring(function.indexOf("(") + 1, function.indexOf(")"));
if (StringUtils.isNotEmpty(params.trim())) {
list = Arrays.asList(params.split(","));
}
// todo 代处理问题,自定义函数接受多个参数
map.put(function, list.isEmpty() ? null : list.get(0));
}
return map;
}
private OperationLog operationLog(Object target, Method method, Object[] args) {
String className = target.getClass().getName();
String traceId = className + "." + method.getName() + "-" + System.currentTimeMillis();
// 参数
String paramMap = methodParamMap(method, args);
// 解析审计日志
Stack<AuditLog> auditLogStack = LogRecordContext.getAuditLog();
if (auditLogStack != null) {
auditLogStack.forEach(o -> o.setTraceId(traceId));
}
// 日志对象
return new OperationLog()
.setTraceId(traceId)
.setParams(paramMap)
.setMethod(method.getName())
.setOperator(operatorGetService.getOperator())
.setOperationTime(LocalDateTime.now())
.setAuditLogList(auditLogStack);
}
private Map<String, String> paramCondition(String description, EvaluationContext evaluationContext, AnnotatedElementKey methodKey) {
Map<String, String> map = new HashMap<>();
List<String> strings = SpelUtils.parseExpression(description);
for (String condition : strings) {
// 执行 condition
Object value = evaluator.condition(condition, methodKey, evaluationContext);
map.put(condition, this.toJson(value));
}
return map;
}
private String parseLogDescription(String description, Map<String, String> map) {
for (Map.Entry<String, String> en : map.entrySet()) {
String p = String.format("{%s}", en.getKey());
description = description.replace(p, en.getValue());
}
return description;
}
/**
* 方法参数获取
*
* @param method 方法
* @return 方法参数,key 参数名称,value 参数值
*/
private String methodParamMap(Method method, Object[] args) {
JSONObject object = new JSONObject();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < args.length; i++) {
object.putOpt(parameters[i].getName(), JSONUtil.toJsonStr(args[i]));
}
return object.toString();
}
private String toJson(Object value) {
if (value == null) {
return "null";
}
if (value instanceof String) {
return String.valueOf(value);
}
if (value instanceof Integer) {
return String.valueOf(value);
}
if (value instanceof Long) {
return String.valueOf(value);
}
if (value instanceof Character) {
return String.valueOf(value);
}
if (value instanceof Double) {
return String.valueOf(value);
}
if (value instanceof Float) {
return String.valueOf(value);
}
if (value instanceof BigDecimal) {
return String.valueOf(value);
}
return JSONUtil.toJsonStr(value);
}
}
配置
@Bean
public LogInterceptor logRecordInterceptor(IFunctionService functionService, IOperatorGetService operatorGetService, ILogRecordService logRecordService) {
// 创建切面拦截器
return new LogInterceptor(operatorGetService, logRecordService, functionService);
}
@Bean
public BeanFactoryLogAdvisor beanFactoryLogRecordAdvisor(@Autowired LogInterceptor interceptor) {
// 切点bean工厂
BeanFactoryLogAdvisor advisor = new BeanFactoryLogAdvisor();
// 绑定切面拦截器
advisor.setAdvice(interceptor);
return advisor;
}