目录
1.aop说明
2.实际应用
2.1 引入aop包
2.2 新增切面类
2.3 execution用法说明
2.4 测试
2.5 出现的问题
3.优化
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是Spring框架中的一个重要内容,它通过对既有程序定义一个切入点,然后在其前后切入不同的执行内容,比如常见的有:打开数据库连接/关闭数据库连接、打开事务/关闭事务、记录日志等。
基于AOP不会破坏原来程序逻辑,因此它可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
而当我们需要使用CGLIB来实现AOP的时候,需要配置spring.aop.proxy-target-class=true,不然默认使用的是标准Java的实现。
实现AOP的切面主要有以下几个要素:
使用@Aspect注解将一个java类定义为切面类
使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。
根据需要在切入点不同位置的切入内容
使用@Before在切入点开始处切入内容
使用@After在切入点结尾处切入内容
使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
org.springframework.boot
spring-boot-starter-aop
package com.hhmt.delivery.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 辉煌明天
* 原文链接:https://blog.csdn.net/weixin_42236404/article/details/89918737
* FileName: LogAop
* Author: huachun
* email: [email protected]
* Date: 2021/12/27 15:51
* Description:
*/
@Aspect
@Component
public class LogAop {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(LogAop.class);
@Pointcut("execution(public * com.hhmt.delivery.*..*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
// 接收到请求,记录请求内容
String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + ":{}";
String methodParams = Arrays.toString(joinPoint.getArgs());
LOGGER.info("params:" + methodName, methodParams);
}
@AfterReturning(returning = "data", pointcut = "webLog()")
public void doAfterReturning(JoinPoint joinPoint, Object data) {
String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + ":{}";
LOGGER.info("return:" + methodName, data);
}
}
第一个 * 指任意访问修饰符
第二个 * 指任何返回类型;
第三个 * 指任何包;
第四个 .*Controller 指任意以Controller结尾的类
第唔个 *(..) 指任意方法
这里不单独写测试类了,直接访问接口查看服务中的日志
2021-12-28 10:59:18,848: INFO http-nio-9527-exec-3 (LogAop.java:35) - params:com.hhmt.delivery.controller.OcpxCustomerController.customerAscribe:[{redis_key=00501-2021122810-d6c7f763836d44409012, event_type=21, event_time=1640660358650}, 00501]
2021-12-28 10:59:18,848: INFO http-nio-9527-exec-3 (LogAop.java:35) - params:com.hhmt.delivery.ocpx.service.OcpxServiceFactory.customerService:[00501]
2021-12-28 10:59:18,849: INFO http-nio-9527-exec-3 (LogAop.java:42) - return:com.hhmt.delivery.ocpx.service.OcpxServiceFactory.customerService:com.hhmt.delivery.ocpx.service.customer.impl.MeiTuanNetWorkCustomerService@793138bd
2021-12-28 10:59:18,849: INFO http-nio-9527-exec-3 (LogAop.java:35) - params:com.hhmt.delivery.ocpx.service.customer.impl.MeiTuanNetWorkCustomerService.customerAscribe:[{redis_key=00501-2021122810-d6c7f763836d44409012, event_type=21, event_time=1640660358650}, 00501]
这样在本地测试环境完全看不出来什么问题,到那时放到线上环境之后,由于使用了负载均衡,会有健康监测,所以一直出现了健康检查日志,这样是很不优雅的而且暂用了内存,所以需要指定一下具体的包解决这个问题
解决方法:
1.指定具体的包路径
下面指定了打印具体的包下面的方法日志,问题解决
@Pointcut("execution(public * com.hhmt.delivery.controller..*(..))" + "||execution(public * com.hhmt.delivery.ocpx..*(..))" + "||execution(public * com.hhmt.delivery.service..*(..))" + "||execution(public * com.hhmt.delivery.dao..*(..))" + "||execution(public * com.hhmt.delivery.async..*(..))" + "||execution(public * com.hhmt.delivery.task..*(..))")
public void webLog() {
}
2.排除健康检查类