SpringBoot实践(三十九):如何使用AOP
  aH6JFbavWGun 2023年12月04日 66 0


目录

直接使用@Aspect

定义切面逻辑

模拟业务代码

测试输出

 自定义注解方式

自定义切面注解

定义切入点逻辑

模拟业务代码

测试输出


面向切面(AOP) 是spring重要特性,在功能上切面编程是面向对象编程的很好的补充,面向对象强调封装和开闭原则,如果多个对象有通用行为和方法,将造成很多冗余代码,AOP将通用功能作为切面插入到业务逻辑中(如通用的日志打印,异常处理,license判断等)抽取通用逻辑,减少代码冗余,并且无侵入地修改代码,在实现层面上都是通过动态代理实现,默认cglib方式,SpringBoot简化了它的使用,常用的2种方式:直接使用aspect注解扫描或基于自定义的注解。

首先在springBoot的依赖管理基础上,引入aop的依赖:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

直接使用@Aspect

定义切面逻辑

使用@Aspect实现一个通用的业务逻辑,比如日志打印,提供了几种切面增强方式:前置增强@Before,后置增强@After,环绕返回@AfterReturning,环绕增强@Around(前后都有),异常抛出增强AfterThrowing,执行顺序是:

  1. 正常情况:@Around-->@Before-->目标方法执行-->@AfterReturning-->@After-->@AfterReturning-->@Around
  2. 异常情况:@Around-->@Before-->目标方法执行-->@AfterThrowing-->@After-->AfterThrowing-->@Around

 如下:

@Component
@Aspect
@Slf4j
public class LoggingAspect {
    @Pointcut("execution(public * com.example.hello.controller.*.*())")
    public void LogAspect(){}
    @Before("LogAspect()")
    public void doBefore(JoinPoint joinPoint){
        log.info(" -------------------------> this is before.");
    }
    @After("LogAspect()")
    public void doAfter(JoinPoint joinPoint){
        log.info(" -------------------------> this is after.");
    }
    @AfterReturning("LogAspect()")
    public void doAfterReturning(JoinPoint joinPoint){
        log.info(" -------------------------> this is afterReturning.");
    }
    @AfterThrowing("LogAspect()")
    public void deAfterThrowing(JoinPoint joinPoint){
        log.info(" -------------------------> this is deAfterThrowing.");
    }
    @Around("LogAspect()")
    public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{
        log.info(" -------------------------> this is deAround.");
        return joinPoint.proceed();
    }
}

模拟业务代码

这里的切入点是controller类中方法,controller的方法定义如下,其中helloService模拟的是真实的业务代码,这个controller不需要做任何修改,测试正常输入和异常输出;

@GetMapping("/hello")
    public String sayHello(){
        log.info("---- 模拟基于标准注解的切面过程 ---------- >running hello");
        return helloService.sayHello();
    }

    @GetMapping("/hello2")
    @LogAnnotation(param = "HelloController")
    public String sayHello2(){
        log.info("---- 模拟异常后切面过程 ---------- >running hello2");
        throw new RuntimeException();
    }

测试输出

 在正常输出业务代码的前后,及方法的全局都被注入了自定义的逻辑: 

SpringBoot实践(三十九):如何使用AOP_自定义注解

异常输出:

SpringBoot实践(三十九):如何使用AOP_spring boot_02

 自定义注解方式

上面的方式可以无侵入地为我们的业务代码增加某些通用逻辑,同时我们也可以自定义注解方式,然后将自定义注解增加到部分业务代码中;

自定义切面注解

定义注解LogAannotation,能够在方法和类上标注,有个参数param默认空;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface LogAnnotation {
    String param() default "";
}

定义切入点逻辑

LoggingAspect2实现了切入点和自定义注解@LogAnnotation的逻辑,在切入点前后执行时间打印;

@Aspect
@Component
@Slf4j
public class LoggingAspect2 {

    @Around("@annotation(logAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) throws Throwable {
        log.info(String.format("time now :%s",new Date()));
        Object o = joinPoint.proceed();
        log.info(String.format("time now :%s",new Date()));
        return o;
    }
}

模拟业务代码

这种方式需要修改业务代码,增加对于自定义注解的传参;

@GetMapping("/hello3")
    @LogAnnotation(param = "HelloController")
    public String sayHello3(){
        log.info("---- 模拟基于自定义注解的切面 ---------- >running hello3");
        return helloService.sayHello();
    }

测试输出

这里因为上面的@aspect注解增加了环绕增强,因此hello3的上下日期打印是自定义注解的实现。

SpringBoot实践(三十九):如何使用AOP_spring_03

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月04日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   53   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   109   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
aH6JFbavWGun
作者其他文章 更多