一、What?
AOP,面向切面编程
- OOP面向对象编程的模式,OOP的主要功能是数据封装、继承和多态。OOP把系统看作多个对象的交互
- AOP是一种新的编程方式,AOP把系统分解为不同的关注点,或者称之为切面
相关概念:
- Aspect:切面,即一个横跨多个核心逻辑的功能,或者称之为系统关注点
- Joinpoint:连接点,即定义在应用程序流程的何处插入切面的执行
- Pointcut:切入点,即一组连接点的集合
- Weaving:织入,指将切面整合到程序的执行流程中
- Target Object:目标对象,即真正执行业务的核心逻辑对象
拦截器有以下类型:
- @Before:这种拦截器先执行拦截代码,再执行目标代码。如果拦截器抛异常,那么目标代码就不执行了;
- @After:这种拦截器先执行目标代码,再执行拦截器代码。无论目标代码是否抛异常,拦截器代码都会执行;
- @AfterReturning:和@After不同的是,只有当目标代码正常返回时,才执行拦截器代码;
- @AfterThrowing:和@After不同的是,只有当目标代码抛出了异常时,才执行拦截器代码;
- @Around:能完全控制目标代码是否执行,并可以在执行前后、抛异常后执行任意拦截代码,可以说是包含了上面所有功能。
二、How?
生产中使用注解装配AOP,不要使用AspectJ的类似execution(* xxx.Xyz.*(..))这样的复杂注解
三、Why?
对于AOP的织入,有3种方式:
- 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入;
- 类加载器:在目标类被装载到JVM时,通过一个特殊的类加载器,对目标类的字节码重新“增强”;
- 运行期:目标对象和切面都是普通Java类,通过JVM的动态代理功能或者第三方库实现运行期动态织入。
Spring的AOP实现就是基于动态代理:
- Spring对接口类型使用JDK动态代理,对普通类使用CGLIB创建子类。如果一个Bean的class是final,Spring将无法为其创建子类。
自动加super()的功能是Java编译器实现的,它发现你没加,就自动给加上,发现你加错了,就报编译错误。但实际上,如果直接构造字节码,一个类的构造方法中,不一定非要调用super()。Spring使用CGLIB构造的Proxy类,是直接生成字节码,并没有源码-编译-字节码这个步骤,所以:
- Spring通过CGLIB创建的代理类,不会初始化代理类自身继承的任何成员变量,包括final类型的成员变量!