AOP快速入门

AOP原理

在不改变原有代码功能的基础上,对功能进行增强,前置增强,后置增强,前后都增强等等,类似拦截器

概念

  • Aspect:切面,即一个横跨多个核心逻辑的功能,或者称之为系统关注点;
  • Pointcut:切入点,即一组连接点的集合;
  • Advice:通知,用来增强功能的方法

通知

前置通知
  • 名称:@Before
  • 位置:方法上方
  • 作用:当前通知方法在原始切入点方法前运行
  • 范例:

~~~java @Before("pt()") public void before() { System.out.println("before advice ..."); } ~~~

后置通知
  • 名称:@After

  • 位置:方法上方

  • 作用:当前通知方法在原始切入点方法后运行

  • 范例:

    ~~~java @After("pt()") public void after() { System.out.println("after advice ..."); } ~~~

环绕通知
  • 名称:@Around(重点,常用)

  • 位置:方法上方

  • 作用:当前通知方法在原始切入点方法前后运行

  • 范例:

    ~~~java @Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice ..."); Object ret = pjp.proceed(); System.out.println("around after advice ..."); return ret; } ~~~

@Around注意事项

  1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知

  2. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行

  3. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

使用

  • 引入依赖

java org.springframework.boot spring-boot-starter-aop

方式一:
  • 定义注解

java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyPointCut { //用来给被增强的方法做标记 }

  • 在需要被增强的方法上加刚才自定义的注解

```java @MyPointCut @RequestMapping public String hello(){ // 需要被增强的方法

System.out.println(articleService.listArticles(new PageParams()));

return "hello";

} ```

  • 定义切面

```java @Aspect @Component @Slf4j public class LogAspect { // 切面

// 定义切点,要对哪个方法增强
// @Pointcut("execution(public * blog.service..*.*(..))")  
// private void pt() {}    打击面太大或太小,不够灵活,一般不用

//定义通知
@Around("@annotation(MyPointCut)")
public Object doLogging(ProceedingJoinPoint pjp) throws Throwable{
    try {
        System.out.println("==========>开始前的逻辑。。。");

        Object ret = pjp.proceed();  // 调用被执行方法

        System.out.println("==========>完成后的逻辑。。。");

        return ret;
    }catch (Exception e){
        log.error("异常信息",e);
        throw e;
    }
}

} ```

方式二
  • 定义切面

```java @Aspect @Component @Slf4j public class LogAspect { // 切面

@Pointcut("execution(public * blog.test.TestService.say())")
public void say() {
}

@Around("say()")
public Object pp(ProceedingJoinPoint pjp) {

    System.out.println("==========>开始前的逻辑。。。");

    Object ret = null;  // 调用被执行方法

    try {
        ret = pjp.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }

    System.out.println("==========>完成后的逻辑。。。");

    return ret;
}

} ```

注意事项

  1. 访问被增强的Bean时,总是调用该Bean的方法,如果访问成员变量会访问不到
  2. 编写Bean时,如果可能会被AOP代理,就不要编写public final方法,会返回空

你可能感兴趣的:(spring,aop,java,spring,boot,lua)