Spring AOP-基础使用

零、本文纲要

  • 一、了解AOP
    1、认识AOP
    2、AOP作用
    3、AOP核心概念
  • 二、AOP快速入门
    1、基础准备
    2、AOP实现
    3、总结
  • 三、AOP获取通知数据
    1、JoinPoint
    2、ProceedingJoinPoint
    3、获取通知数据的使用场景

一、了解AOP

1、认识AOP

AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。

2、AOP作用

在不侵入原始设计的基础上,进行功能增强。

3、AOP核心概念

  • ① 连接点 Join Point

程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。在Spring AOP中可以理解为执行方法。

  • ② 切入点 Pointcut

匹配连接点的式子,可以匹配一个或者多个。

  • ③ 通知 Advice

在切入点处执行的操作,共性功能。

  • ④ 切面 Aspect

描述通知Advice与切入点Pointcut的关系。

  • ⑤ 通知类

定义通知的类。

二、AOP快速入门

1、基础准备

  • ① 导入依赖

Ⅰ spring-context:spring核心容器bean、context相关;


  org.springframework
  spring-context
  5.2.10.RELEASE

其中该依赖包含了AOP相关的依赖内容,如下:

spring中包含aop相关依赖.png

Ⅱ aspectjweaver:AOP需要的依赖;


  org.aspectj
  aspectjweaver
  1.9.4

  • ② 编写接口与实现类
public interface BookDao {
    public void save();
    public void update();
}

@Repository
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("book dao save ...");
    }

    public void update(){
        System.out.println("book dao update ...");
    }
}
  • ③ 创建Spring配置类
@Configuration
@ComponentScan("com.stone")
public class SpringConfig {
}
  • ④ 编写运行类
public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = ctx.getBean(BookDao.class);
        bookDao.save();
    }
}

2、AOP实现

  • ① 定义通知类和通知 Advice
public class MyAdvice {
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}
  • ② 定义切入点 Pointcut
//设置切入点,要求配置在方法上方
@Pointcut("execution(void com.stone.dao.BookDao.update())")
private void pt(){}
  • ③ 制作切面 Aspect

我们知道切面是用于描述通知Advice与切入点Pointcut的关系,此处我们在通知Advice上使用@Before注解,描述"pt()"与method通知的关系,如下:

//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(){
    System.out.println(System.currentTimeMillis());
}
  • ④ 将通知类配置给Context容器并标识为切面类

在我们的通知类上添加@Component注解和@Aspect注解,如下:

@Component
@Aspect
public class MyAdvice {
    ... ...
}
  • ⑤ 开启注解格式AOP功能

在我们的配置类上添加@EnableAspectJAutoProxy注解,开启注解格式AOP功能,如下:

@Configuration
@ComponentScan("com.stone")
@EnableAspectJAutoProxy //开启注解格式AOP功能
public class SpringConfig {
}
  • ⑥ 测试

3、总结

  • ① 相关注解

@EnableAspectJAutoProxy:用于配置类上,开启注解格式AOP功能;
@Aspect:用于切面类上,设置当前类为AOP切面类;
@Pointcut:用于切点空方法上,设置切入点方法;
@Before、@After、@Around、@AfterReturning、@AfterThrowing:用于通知方法上方,设置当前通知方法与切入点之间绑定关系。

  • ② 切入点表达式

切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)

*:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现;
..:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写;
+:专用于匹配子类类型。

三、AOP获取通知数据

1、JoinPoint

我们可以在对应的通知内传入参数JoinPoint,其可以帮助我们获取被增强方法所传递的参数,具体如下:

@Before("pt()")
public void method(JoinPoint joinPoint){
    Object[] args = joinPoint.getArgs();
}
  • ① 测试

Ⅰ 准备接口及实现类

public interface BookDao {
    public void update(String text);
}

@Repository
public class BookDaoImpl implements BookDao {
    public void update(String text){
        System.out.println("book dao update ..." + text);
    }
}

Ⅱ 修改织入

a、切点表达式处添加了参数String类型;
b、通知方法内添加了参数获取与打印;

//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
    //设置切入点,要求配置在方法上方
    @Pointcut("execution(void com.itheima.dao.BookDao.update(String))")
    private void pt(){}

    //设置在切入点pt()的前面运行当前操作(前置通知)
    @Before("pt()")
    public void method(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println("args is: " + Arrays.toString(args));
        System.out.println("before advice ..." );
    }
}

Ⅲ 测试类测试

bookDao.update("Hello JoinPoint!");
JoinPoint获取通知数据.png
  • ② 总结

JoinPoint是非环绕通知采用的获取方式,如:@Before、@After。

2、ProceedingJoinPoint

环绕通知使用的是ProceedingJoinPoint,因为ProceedingJoinPoint是JoinPoint类的子类,所以对于ProceedingJoinPoint类中应该也会有对应的getArgs()方法。

  • ① 测试

Ⅰ 修改接口和实现类方法

此处我们添加了返回值的设置,如下:

public Integer update(String text); // 接口中

public Integer update(String text){ // 实现类中
    System.out.println("book dao update ..." + text);
    return 200;
}

Ⅱ 修改切点表达式

由于我们设置了返回值,此处修改表达式中的对应返回值部分,如下:

@Pointcut("execution(Integer com.itheima.dao.BookDao.update(String))")

Ⅲ 添加织入

Object result = joinPoint.proceed();相比于前者,ProceedingJoinPoint多了执行原方法的逻辑,而且可以获得返回值,如下:

@Around("pt()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    Object[] args = joinPoint.getArgs();
    System.out.println("args is: " + Arrays.toString(args));
    System.out.println("before advice ...");
    Object result = joinPoint.proceed(args);
    System.out.println(result); // 打印返回值
    System.out.println("after advice ...");
    return result;
}

Ⅲ 测试类测试

ProceedingJoinPoint.png
  • ② 总结

ProceedingJoinPoint用于@Around环绕通知的情形。

3、获取通知数据的使用场景

如:对传入密码的或者其他字符串的统一去除首位空格的操作。

@Around("DataAdvice.servicePt()")
// @Around("servicePt()")这两种写法都对
public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
    //获取原始方法的参数
    Object[] args = pjp.getArgs();
    for (int i = 0; i < args.length; i++) {
        //判断参数是不是字符串
        if(args[i].getClass().equals(String.class)){
            args[i] = args[i].toString().trim();
        }
    }
    //将修改后的参数传入到原始方法的执行中
    Object ret = pjp.proceed(args);
    return ret;
}

此通知中,我们就能实现对对应字符串进行trim操作。

四、结尾

以上即为Spring AOP基础使用的全部内容,感谢阅读。

你可能感兴趣的:(Spring AOP-基础使用)