spring boot Aop面向切面
前置通知(Before):在目标方法被调用之前调用通知功能
后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
返回通知(After-returning):在目标方法成功执行之后调用通知
异常通知(After-throwing):在目标方法抛出异常后调用通知
环绕通知(Around):通知包裹了被通知的方法,在被通知的方
法调用之前和之后执行自定义的行为
引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>

配置1:
spring.aop.proxy-target-class: true#true表示系统底层会基于CGLIB方式为目标对象创建代理对象
代理对象为目标对象的子类对象,在控制层可以直接使用目标类来注入

配置2:
spring.aop.proxy-target-class: false#false表示系统底层会基于JDK方式为目标对象创建代理对象
代理对象为目标对象的兄弟对象,不能使用目标类注入,需要通过接口来注入


/**
* @Aspect 注解描述的类为spring容器中的一个切面对象类型(此类型中封装切入点与通知方法) 1)切入点:(要执行拓展业务的方法的集合)
* 2)通知方法:封装了在切入点方法上要执行的拓展业务方法.
*/
//@Order(1)
@Slf4j
@Aspect
@Component
public class SysLogAspect {
// private static final Logger log=LoggerFactory.getLogger(SysLogAspect.class);
/**
* @Pointcut 注解用于描述切入点(在哪些点上执行拓展业务)
* bean(bean对象名字):为一种切入点表达式(这个表达式中定义了哪个或哪些bean对象的方法要进行功能扩展).
* 例如,bean(sysUserServiceImpl)表达式表示名字为sysUserServiceImpl的bean对象中所有方法的集合为切入点,
* 也就是说这个sysUserServiceImpl对象中的任意方法执行时都要进行功能扩展.
*/
@Pointcut("bean(sysUserServiceImpl)")
// @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
public void doLogPointCut() {
}// 此方法内部不需要写具体实现(方法的方法名也是任意)
/**
* Around注解描述的方法为一个通知方法(服务增益方法),此方法内部可以做服务增益(拓展业务),@Around注解
* 内部要指定切入点表达式,在此切入点表达式对应的切入点方法上做功能扩展.
*
* @param jp 表示连接点,连接点是动态确定的,用于封装正在执行的切入点方法(目标方法)信息.
* @return 目标方法的执行结果
* @throws Throwable 通知方法执行过程中出现的异常
*/
@Around("doLogPointCut()")
public Object doLogAround(ProceedingJoinPoint jp) throws Throwable {
// 1.记录方法开始执行时间
try {
long t1 = System.currentTimeMillis();
log.info("start:{}", t1);
// 2.执行目标方法
Object result = jp.proceed();// 最终(中间还可以调用本类其它通知或其它切面的通知)会调用目标方法
// 3.记录方法结束执行时间
long t2 = System.currentTimeMillis();
log.info("after:{}", t2);
// String targetClassMethod = getTargetClassMethod(jp);
// log.info("{}目标方法执行耗时:{}", targetClassMethod, (t2 - t1));
// 4.将正常行为日志信息写入到数据库
// saveUserLog(jp, (t2 - t1));// new Thread(){}.start()
// 5.返回目标方法执行结果
return result;// 目标方法的返回结果
} catch (Throwable e) {
log.error("目标方法执行时出现了异常:{}", e.getMessage());
throw e;
}
}
}
/**获取目标方法的全限定名(目标类全名+方法名)*/
private String getTargetClassMethod(ProceedingJoinPoint jp) {
// 1.获取目标对象类型
Class<?> targetCls = jp.getTarget().getClass();
// 2.获取目标对象类型的类全名
String targetClsName = targetCls.getName();
// 3.获取目标方法名
// 3.1获取方法签名(方法签名对象中封装了方法相关信息)
// Signature s=jp.getSignature();
MethodSignature ms = (MethodSignature) jp.getSignature();
// 3.2基于方法签名获取方法名
// String methodName=s.getName();
String methodName = ms.getName();
// 4.构建方法的全限定名并返回
return targetClsName + "." + methodName;
}

浙公网安备 33010602011771号