[toc]

Lecture11-切面-AOP相关概念
1、AOP概念介绍
①名词解释
AOP:Aspect Oriented Programming 面向切面编程
②AOP的作用
下面两点是同一件事的两面,一枚硬币的两面:
- 简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。
- 代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了。
2、横切关注点
从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。
这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。

3、通知
每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。
- 前置通知:在被代理的目标方法前执行
- 返回通知:在被代理的目标方法成功结束后执行(寿终正寝)
- 异常通知:在被代理的目标方法异常结束后执行(死于非命)
- 后置通知:在被代理的目标方法最终结束后执行(盖棺定论)
- 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置

4、切面
封装通知方法的类

5、目标
被代理的目标对象。
6、代理
向目标对象应用通知之后创建的代理对象。
7、连接点
这也是一个纯逻辑概念,不是语法定义的。
把方法排成一排,每一个横切位置看成x轴方向,把方法从上到下执行的顺序看成y轴,x轴和y轴的交叉点就是连接点。

8、切入点
定位连接点的方式。
每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物(从逻辑上来说)。
如果把连接点看作数据库中的记录,那么切入点就是查询记录的 SQL 语句。
Spring 的 AOP 技术可以通过切入点定位到特定的连接点。
切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件
9、基于注解的AOP用到的技术[参考资料]
在Spring AOP中,代理创建的机制确实与版本和配置有关。你观察到的现象可能与以下几个因素有关:
①代理机制的历史变化
- Spring 5及以前:默认策略是:
- 有接口实现:使用JDK动态代理(
Proxy.newProxyInstance) - 无接口:使用CGLIB代理
- 有接口实现:使用JDK动态代理(

- 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。
- cglib:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口。
- AspectJ:本质上是静态代理,将代理逻辑“织入”被代理的目标类编译得到的字节码文件,所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
-
Spring 6:默认使用强制CGLIB代理,无论目标类是否实现接口。这一变化在Spring 6.0的官方文档中有明确说明:
"Since Spring Framework 6.0, the proxy-target-class attribute defaults to true, meaning that CGLIB proxies are used by default even for classes that implement interfaces."
②强制CGLIB代理的配置方式
在Spring 6中,以下配置会强制使用CGLIB代理:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
// 配置类内容
}
注意,从Spring 6开始,proxyTargetClass的默认值已经是true,所以无需显式设置。
③如何切换回JDK动态代理(如果需要)
如果你希望恢复到旧的行为(有接口时使用JDK代理),可以显式配置:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false) // 强制使用JDK代理(有接口时)
public class AppConfig {
// 配置类内容
}
④两种代理方式的区别
| JDK动态代理 | CGLIB代理 |
|---|---|
| 基于接口实现 | 基于类继承(通过字节码生成子类) |
| 只能代理实现了接口的类 | 可以代理任何类(除final类/final方法) |
| 性能略高(直接调用接口方法) | 性能稍低(通过子类调用) |
⑤为何Spring 6默认使用CGLIB?
- 简化代理策略:统一使用CGLIB,避免开发者因接口存在与否而产生困惑。
- 功能完整性:CGLIB支持代理类的所有方法,而JDK代理只能代理接口中定义的方法。
- 现代应用趋势:越来越多的Spring应用使用@Component等注解,类通常不实现特定接口。
⑥总结
如果你在Spring 6中发现AOP始终使用CGLIB,这是默认行为,而非配置错误。如果需要恢复到旧的JDK代理策略,可以通过@EnableAspectJAutoProxy(proxyTargetClass = false)显式配置。这种变化不会影响大多数应用,但在需要细粒度控制代理行为的场景下需要注意。