ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

SpringBoot使用Aspect AOP注解实现日志管理(一)

2021-07-29 12:00:26  阅读:273  来源: 互联网

标签:info SpringBoot 切入点 joinPoint Pointcut Aspect AOP public log


SpringBoot使用Aspect AOP注解实现日志管理(一)

回顾AOP

aop,又叫面向切面编程,通俗理解就是,将那些与业务无关,却为业务模块所共同调用的逻辑代码封装起来,形成一个切面,减少重复代码,降低模块间的耦合度,方便后期操作和维护。

Spring AOP和Aspect AOP

Spring AOP属于运行时的增强,而Aspect AOP属于编译时的增强。SpringAOP是基于代理(Proxying),而AspectAOP是基于字节码操作。如果切面比较少,两者差不多,如果切面太多,最好使用AspectAOP,它比SpringAOP快很多。

使用spring-boot-starter-aop启动器默认帮我们引入了对Aspectj的实现
在这里插入图片描述

常用注解使用

 @Aspect -- 作用是把当前类标识为一个切面供容器读取
 @Pointcut -- (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
 @Before -- 标识一个前置增强方法,相当于BeforeAdvice的功能
 @AfterReturning -- 后置增强,相当于AfterReturningAdvice,方法退出时执行
 @AfterThrowing -- 异常抛出增强,相当于ThrowsAdvice
 @After -- final增强,不管是抛出异常或者正常退出都会执行
 @Around -- 环绕增强,相当于MethodInterceptor

@Aspect

@Aspect– 作用是把当前类标识为一个切面供容器读取

@Aspect
@Component
@Slf4j
public class LogAspect {
}

@Pointcut

@Pointcut -- (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式或者基于注解的切入点

基于注解的切入点

@Pointcut("@annotation(cn.zysheep.annotation.Log)")
//@annotation(cn.zysheep.annotation.Log),为自定义注解
public void Pointcut() {}

基于切入点表达式
execution()是最常用的切点函数

@Pointcut("execution(* cn.zysheep.springaop.service.impl..*.*(..))")
public void Pointcut() {}

整个表达式可以分为四个部分:
1. 第一个*号:表示返回类型, *号表示所有的类型
2. 包名: 表示需要拦截的包名,后面的..表示当前包和当前包的所有子包,cn.zysheep.springaop.service.impl包、子孙包下所有类的方法。
3. 第二个*号: 表示类名,*号表示所有的类。
4. *(..):最后这个星号表示方法名, *号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

// cn.zysheep.controller包中所有的类的所有方法切面
// @Pointcut("execution(public * cn.zysheep.controller.*.*(..))")

// 只针对 UserController 类切面
// @Pointcut("execution(public * cn.zysheep.controller.UserController.*(..))")

// 统一切点,对cn.zysheep及其子包中所有的类的所有方法切面
// @Pointcut("execution(* cn.zysheep.controller.*.*(..))")

个人认为基于注解的方式可以实现更加细粒度的操作,比如日志管理,只要自己声明一个自定义的注解@Log,可以在任意三层中定义到不同的方法中

@Before

标识一个前置增强方法,相当于BeforeAdvice的功能

//@Before: 前置通知 ,Pointcut()定义的切入点函数
 @Before("Pointcut()")
 public void beforeMethod() {
     log.info("调用了前置通知");
 }

@AfterReturning

后置增强,相当于AfterReturningAdvice,方法退出时执行

 //@AfterRunning: 返回通知    result为切入点返回内容
@AfterReturning(value="Pointcut()",returning="result")
public void afterReturningMethod(JoinPoint joinPoint,Object result){
    log.info("调用了返回通知,result :{}",result);
}

@AfterThrowing

异常抛出增强,相当于ThrowsAdvice

//@AfterThrowing: 异常通知  e为切入点执行异常的信息
 @AfterThrowing(value="Pointcut()",throwing="e")
 public void doAfterThrowing(JoinPoint joinPoint, Exception e){
     log.info("调用了异常通知  joinPoint:{},e :{}",joinPoint, e.getStackTrace());
 }

@After

final增强,不管是抛出异常或者正常退出都会执行

//@After: 后置通知
@After("Pointcut()")
public void afterMethod(JoinPoint joinPoint){
	//joinPoint: 当前的连接点,即执行的切入点
    log.info("调用了后置通知,joinPoint:{}",joinPoint);
}

@Around

环绕增强,相当于MethodInterceptor

//@Around: 环绕通知
@Around("Pointcut()")
public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    log.info("around执行方法之前");
    // 执行方法
    Object object = proceedingJoinPoint.proceed();
    // 执行时长(毫秒)
    long time = System.currentTimeMillis() - beginTime;
    log.info("around执行方法之后--返回值: " +object);
    return object;
}

基于注解的切入点测试

在这里插入图片描述

pom

<parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.4.0</version>
</parent>
 
<dependencies>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-aop</artifactId>
	</dependency>
	
	<dependency>
	    <groupId>org.projectlombok</groupId>
	    <artifactId>lombok</artifactId>
	</dependency>
</dependencies>

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    //模块名
    String value() default "";
}

定义一个切面

@Aspect
@Component
@Slf4j
public class LogAspect {

    long beginTime;

    @Pointcut("@annotation(cn.zysheep.annotation.Log)")
    public void Pointcut() {}

    @Before("Pointcut()")
    public void beforeMethod() {
        log.info("调用了前置通知@Before");
        beginTime = System.currentTimeMillis();
    }

    @AfterReturning(value="Pointcut()",returning="result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result){
        log.info("调用了返回通知@AfterReturning,result :{}",result);
    }

    @AfterThrowing(value="Pointcut()",throwing="e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e){
        log.info("调用了异常通知@AfterThrowing  joinPoint:{},e :{}",joinPoint,  e.getMessage());
    }

    @After("Pointcut()")
    public void afterMethod(JoinPoint joinPoint){
        //joinPoint: 当前的连接点,即执行的切入点
        log.info("调用了后置通知@After,joinPoint:{}",joinPoint);
    }

    @Around("Pointcut()")
    public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("@Around执行方法之前");
        // 执行方法
        Object object = proceedingJoinPoint.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        log.info("@Around执行方法之后--返回值: " +object);
        return object;
    }
}

controller

@RestController
@Slf4j
public class TestAopController {

    @GetMapping("/save")
    @Log("保存数据")
    public String save() {
        log.info("执行了controller中的save方法");
        return "保存数据";
    }
}

启动类

@SpringBootApplication
public class AOPApplication {
    public static void main(String[] args) {
        SpringApplication.run(AOPApplication.class,args);
    }
}

在这里插入图片描述
执行流程:

  1. @Around前置增强
  2. @Before前置通知
  3. 执行了controller中的save方法
  4. @AfterReturning返回通知
  5. @After后置通知
  6. @Around后置增强

如果切入点出现异常:
在这里插入图片描述
在这里插入图片描述
执行流程:

  1. @Around前置增强
  2. @Before前置通知
  3. 执行了controller中的save方法,如果异常在之前执行,不会输出
  4. @AfterThrowing异常通知
  5. @After后置通知

标签:info,SpringBoot,切入点,joinPoint,Pointcut,Aspect,AOP,public,log
来源: https://blog.csdn.net/qq_45297578/article/details/119205262

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有