hooyantsing's Blog

P24 - P32 AOP

字数统计: 1.3k阅读时长: 5 min
2022/05/30

视频源:尚硅谷Spring框架视频教程(spring5源码级讲解)

AOP(概念)

1. 什么是 AOP

  • 不通过修改源码方式,在主干功能里面添加新功能。
  • 将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将他们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

AOP(底层原理)

P27

AOP 底层使用动态代理

有两种情况动态代理:

  • 有接口情况,使用 JDK 动态代理
    1. 调用 java.lang.reflect.Proxy 类里的 newProxyInstance 方法;
      • 参数一:类加载器;
      • 参数二:被代理类实现的接口,支持多个接口;
      • 参数三:实现 InvocationHandler 接口,写增强方法。
    2. 编写 JDK 动态代理代码;
    3. 使用 Proxy 类创建接口代理对象。
  • 没有接口情况,使用 CGLIB 动态代理

AOP(术语)

P28

1. 连接点

类里面哪些方法可以被增强,这些方法称为连接点。

2. 切入点

实际被真正增强的方法,称为切入点。

3. 通知(增强)

增强的逻辑部分被称为通知(增强)。

通知有多种类型:

  • 前置通知 @Before
  • 后置通知 @After
  • 环绕通知 @Around
  • 异常通知 @AfterThrowing
  • 最终通知 @AfterReturing

4. 切面

把通知应用到切入点的过程,称为切面。

AOP 操作(准备)

P29

1. Spring 框架一般基于 AspectJ 实现 AOP 操作

什么是 AspectJ ?

AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spring 框架一起使用,进行 AOP 操作。

2. 基于 AspectJ 实现 AOP 操作

  1. 基于 xml 配置文件实现;
  2. 基于注解方式实现。

3. 在项目工程里面引入 AOP 相关依赖

4. 切入点表达式

  1. 切入点表达式的作用:知道对哪个类里面的哪个方法进行增强;
  2. 语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表])

eg 01 对 com.atguigu.dao.BookDao 类里面的 add 进行增强

1
2
3
4
5
// 权限修饰符 * 表示任意权限
// 返回类型 可以省略
// 参数列表 .. 表示全部参数

execution(* com.atguigu.dao.BookDao.add(..));

eg 02 对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强

1
execution(* com.atguigu.dao.BookDao.*(..));

eg 03 对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强

1
execution(* com.atguigu.dao.*.*(..));

AOP 操作(AspectJ 注解)

1. 创建类,在类里面定义方法

2. 创建增强类(编写增强逻辑)

3. 进行通知的配置

  1. 在 spring 配置文件中,开启注解扫描;

    1
    2
    <!-- 开启注解扫描 -->
    <context:component-san base-package="com.atguigu.spring5.aopanno"></context:component-san>

    需要加入 context 和 aop 命名空间。

  2. 使用注解创建 User 和 UserProxy 对象;

  3. 在增强类上面添加 @Aspect 注解;

    被增强类:

    1
    2
    3
    4
    5
    6
    @Component
    public class User {
    public void add() {
    System.out.println("add...");
    }
    }

    增强类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Component
    @Aspect // 生成代理对象
    public class UserProxy {

    // 前置通知
    @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void before() {
    System.out.println("before...");
    }

    // 环绕通知
    @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    System.out.println("环绕之前...");
    proceedingJoinPoint.proceed();
    System.out.println("环绕之后...");
    }
    }
  4. 在 spring 配置文件中开启生成代理对象。

    1
    2
    <!-- 开启 Aspect 生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    可以用配置类的注解代替:@EnableAspectJAutoProxy(proxyTargetClass = true)

    1
    2
    3
    4
    5
    6
    @Configuration // 作为配置类,替代xml配置文件
    @ComponentScan(basePackages = {"com.atguigu"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class SpringConfig {

    }

5. 相同切入点抽取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
@Aspect // 生成代理对象
public class UserProxy {

// 相同切入点抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointdemo() {}

// 前置通知
@Before(value = "")
public void before(pointdemo()) {
System.out.println("before...");
}
}

6. 有多个增强类对同一个方法进行增强,设置增强类优先级

在增强类上面添加注解 @Order(数字类型值),数字类型值越小,优先级越高。

1
2
3
4
5
6
@Component
@Aspect // 生成代理对象
@Order(1)
public class UserProxy {
// more code ...
}

AOP 操作(AspectJ 配置文件)

P32

配置文件方式不常用,多用注解方式(上一节)。

1. 创建两个类,被增强类和增强类,创建方法

被增强类:

1
2
3
4
5
public class Book {
public void buy() {
System.out.println("buy...");
}
}

增强类:

1
2
3
4
5
public class BookProxy {
public void before() {
System.out.println("before...");
}
}

2. 在 spring 配置文件中创建两个类对象

1
2
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>

3. 在 spring 配置文件中配置切入点

1
2
3
4
5
6
7
8
9
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.BookProxy.buy(..))"/>
<!-- 切面 -->
<aop:aspect ref="bookProxy">
<!-- 增强作用在具体的方法上 -->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>

4. 完全使用注解开发

1
2
3
4
5
6
@Configuration // 作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {

}
CATALOG
  1. 1. AOP(概念)
    1. 1.1. 1. 什么是 AOP
  2. 2. AOP(底层原理)
    1. 2.1. AOP 底层使用动态代理
  3. 3. AOP(术语)
    1. 3.1. 1. 连接点
    2. 3.2. 2. 切入点
    3. 3.3. 3. 通知(增强)
    4. 3.4. 4. 切面
  4. 4. AOP 操作(准备)
    1. 4.1. 1. Spring 框架一般基于 AspectJ 实现 AOP 操作
    2. 4.2. 2. 基于 AspectJ 实现 AOP 操作
    3. 4.3. 3. 在项目工程里面引入 AOP 相关依赖
    4. 4.4. 4. 切入点表达式
  5. 5. AOP 操作(AspectJ 注解)
    1. 5.1. 1. 创建类,在类里面定义方法
    2. 5.2. 2. 创建增强类(编写增强逻辑)
    3. 5.3. 3. 进行通知的配置
    4. 5.4. 5. 相同切入点抽取
    5. 5.5. 6. 有多个增强类对同一个方法进行增强,设置增强类优先级
  6. 6. AOP 操作(AspectJ 配置文件)
    1. 6.1. 1. 创建两个类,被增强类和增强类,创建方法
    2. 6.2. 2. 在 spring 配置文件中创建两个类对象
    3. 6.3. 3. 在 spring 配置文件中配置切入点
    4. 6.4. 4. 完全使用注解开发