AOP
AOP,面向切面编程,是IOC的一个拓展功能,是在IOC的基础上通过动态代理来实现的。动态代理生成的是bean对象的代理对象,也就是对bean的拓展,因此是在BeanPostProcessor的后置处理方法中实现的。
在OOP(面向对象编程)中,我们以类Class作为基本单元。在AOP中,我们以Aspect切面作为基本单元。切面,就是将那些与业务无关、却被多个业务模块共同调用的逻辑封装起来,比如日志功能。这样做可以减少系统内的重复代码,降低模块间的耦合度,并有利于后期的可操作性和可维护性。
1. AOP为什么要使用代理来实现?使用的是静态代理还是动态代理?
在Java使用代理,通常是为了在不修改原有类代码的基础上,对类实现扩展和增强,而这正是AOP所追求的功能。比如一个Human类,需要在它的每个方法被调用时在日志中记录调用时间。想要实现这个功能,我们当然可以直接修改Human类内部的方法,在每个方法内实现日志操作。但是很多时候最好不要动原始代码(遵循开放封闭原则OCP),这时候通过代理来实现对Human类的扩展与增强是最好的办法。
代理分为静态代理与动态代理两大类,我们知道Java的代理分为静态代理和动态代理。那么,AOP要用静态代理还是动态代理来实现呢?如果单论Human类,且内部方法少的话,直接用静态代理可能比较方便,只需要Human类与Human代理类实现同一个接口即可。但是AOP往往涉及一个包内的多个类、甚至多个包内的多个类,因此用动态代理在运行期间动态生成代理类会更加的方便。
Spring AOP是基于动态代理实现的,包括JDK动态代理和CGLIB动态代理。AOP是在bean生命周期中的BeanPostProcessor中实现的,从BeanPostProcessor接口内部的两个方法往下找,均可以找到AOP代理的最终两个实现类,如下图。
在Spring2.0以后,Spring也增加了对于AspectJ切点表达式的支持。
2. AOP的底层实现原理?
- 首先确定advice、切面、切点。
- 通过jdk或者cglib的方式来生成代理对象。
- 从DynamicAdvisedInterceptor中的intercept方法开始执行。
- 根据之前定义好的通知来生成拦截器链。
- 从拦截器连依次获取每一个通知开始执行。在执行过程中,为了方便找到下一个通知,会有一个
CglibMethodInvocation
对象。
3. jdk和cglib的动态代理有什么区别?
- JDK动态代理:只提供接口的代理,不支持类的代理;通过反射接收被代理的类,且要求被代理的类必须实现一个接口,代理类需要实现
java.lang.reflect.InvocationHandler
接口,然后通过java.lang.reflect.Proxy.newProxyInstance()
创建代理对象 - CGLIB动态代理:如果目标类没有实现上面接口,Spring AOP会选择CGLIB来实现动态代理。CGLIB ( Code Generation Library ),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意, CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的;且类内被final修饰的方法无法使用CGLIB来进行增强。