文章目录
什么是 AOP?
- 面向切面编程(Aspect Oriented Programming,简称 AOP),是一种编程思想,可以说是面向对象编程(Object Oriented Programing,简称 OOP)的补充和完善。它是一种可以在
运行时
或者编译期、类加载期
将代码切入到类的指定方法或位置上的编程思想。
AOP 常见使用场景
日志场景
,方法前后打印相关信息,比如入参、出参、执行时间等统计场景
- 方法调用次数
- 执行异常次数
- 数据抽样
- 数值累加
安全场景
- 熔断,如:Netflix Hystrix
- 限流和降级,如:Alibaba Sentinel
- 认证和授权,如:Spring Security
- 监控,如:JMX
性能场景
- 缓存,如:Spring Cache
- 超时控制
什么是连接点、切点、增强、引介、切面、目标、代理、织入?
- 连接点(Joinpoint)
- 程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring 仅支持方法的连接点。
- 切点(Pointcut)
- 如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP 的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。
- 增强(Advice)
- 增强是织入到目标类连接点上的一段程序代码。
- 引介(Introduction)
- 引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
- 切面(Aspect)
- 切面是由切点(Pointcut)和增强(Advice)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
- 目标(Target)
- 即被通知的对象,如果没有 AOP,那么通知的逻辑就要写在目标对象中,有了 AOP 之后它可以只关注自己要做的事。
- 代理(Proxy)
- 代理是通知目标对象后创建的对象,从客户端的角度看,代理对象和目标对象是一样的。
- 织入(Weaving)
- 织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式
- ①编译期织入:需要特殊的 Java 编译器(例如 AspectJ 的 ajc)
- ②类加载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强
- ③运行时织入:在运行时为目标类生成代理实现增强。
- Spring 采用了动态代理的方式实现了运行时织入,而 AspectJ 采用了编译期织入和装载期织入的方式。
有哪些类型的通知(Advice),以及它们的 XML 标签和注解实现是什么?
通知类型 | 英文描述 | 注解实现 | XML 标签 |
---|---|---|---|
环绕通知 | Around Advice | @Around | <aop:around/> |
前置通知 | Before Advice | @Before | <aop:before/> |
后置通知 | After Advice | @After | <aop:after/> |
成功执行方法之后的返回通知 | AfterReturning Advice | @AfterReturning | <aop:after-returning/> |
抛出异常之后的异常通知 | AfterThrowing Advice | @AfterThrowing | <aop:after-throwing/> |
AOP 有哪些实现方式?
实现 AOP 的技术,主要分为两大类:
- 静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;
- 编译时编织(特殊编译器实现);
- 类加载时编织(特殊的类加载器实现)。
- 动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。
- JDK 动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类 。
- CGLIB 动态代理:如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类 。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。
Spring AOP 和 AspectJ AOP 有什么区别?
- AspectJ 是 AOP 完整实现,Spring AOP 则是部分实现,Spring AOP 需要依赖 IoC 容器来管理,并且只能作用于 Spring 容器,使用纯Java代码实现。
- Spring AOP 基于动态代理来实现,如果使用接口的,用 JDK 动态代理实现,如果是方法则使用 CGLIB 动态代理实现。
- AspectJ 属于静态织入,包括编译期织入和类加载时织入。
- Spring AOP 仅支持方法级别的 Pointcuts。