一、AOP概述。
AOP(Aspect Oriented Programming)意为面向切面编程设计思想,是对OOP(Object Oriented Programming,面向对象编程语言)的延伸。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ---------- AOP 设计思想
它是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合降低,提高程序的可重用性,同时提高了开发的效率。
其主要功能:日志记录,性能统计监控,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
AOP是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
二、Spring框架对AOP的实现。
- 在Spring1.2版本开始,开始支持AOP技术(即传统Spring AOP)
Spring AOP采用纯JAVA编程实现,不需要专门的编译过程和类加载器,在运行期通过代理向目标尖织入增强代码
- Spring 2.0后,为了简化AOP开发,开始支持AspectJ(第三方AOP框架)
AspectJ是一个基于JAVA语言的AOP框架,从Spring 2.0开始,传统Spring AOP引入了对Aspect支持。
三、AOP的相关术语。
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
- Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
- Target(目标对象):代理的目标对象
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程 spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
- Aspect(切面): 是切入点和通知(引介)的结合
四、Spring AOP的底层实现。
Spring的代理实现有两种,JDK动态代理与Cglib动态代理
Spring底层代理实现机制
1JDK动态代理。
通过JDK api内置的Proxy类来为目标对象创建代理(基于接口)
动态代理:在程序运行时,运用反射机制动态创建而成。
在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
因此存在局限性:必须要求target目标实现接口。
public class JdkProxyFactory implements InvocationHandler { // 被代理对象 private Object target; // 在构造方法对象时,传入被代理对象 public JdkProxyFactory(Object target) { this.target = target; } // 创建代理 public Object createProxy() { // 三个参数: 类加载器、 实现接口、 invocationhandler return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("记录日志!!!!!!"); // 调用目标真实方法 // target 被代理对象, args 方法参数 , method 被调用的方法 return method.invoke(target, args); } }
2、Cglib动态代理
CGLIB(CodeGeneration Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
Java动态代理依赖接口实现,如果被代理类未实现接口,则需要用到Cglib动态代理。
Cglib 不但可以对接口进行代理,也可以对目标类对象实现代理(解决了 Jdk 依赖接口实现代理的问题 )
下载网址: http://sourceforge.net/projects/cglib/files/
------- 在spring3.2版本 core包中内置cglib 类
Cglib的原理是对指定的目标类生成一个子类,并覆盖其中的方法实现增强,由于采用的是继承,所以不能对final修饰的类进行代理
Cglib 创建代理思想: 对目标类创建子类对象
设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)
设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )
在cglib的callback函数中,要执行被代理对象的方法
method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args);public class CglibProxyFactory implements MethodInterceptor { // 被代理目标对象 private Object target; // 在构造工厂时传入被代理对象 public CglibProxyFactory(Object target) { this.target = target; } // 创建代理对象方法 public Object createProxy() { // 1、 创建Enhancer对象 Enhancer enhancer = new Enhancer(); // 2、 cglib创建代理,对目标对象,创建子类对象 enhancer.setSuperclass(target.getClass()); // 3、传入 callback对象,对目标增强 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("记录日志......"); // 按照JDK编程 return method.invoke(target, args); } }