Aspect Oriented Programming 面向切面编程
1.
业界 AOP 实际上 OOP (面向对象编程 ) 延伸 ---- OOP编程语言、 AOP设计思想,下面给出一张AOP的设计思想图。
看左边的的图,UserDao里面定义了两个方法,save方法还有delete方法,我想在执行这两个方法的时候都能打印出日志。java的方法是采用继承,我们写一个抽象的类(Basedao),里面定义了public void writeLog()这个打印日志的方法。然后让UserDao这个类继承BaseDao这样可以实现我要的功能,但是,这么做的话,有一个问题,这样做就破坏了类的结构,因为一个类继承了另外一个类的话会相当于多了一些父类的方法,这样做不好,是属于侵入式复用。所以提出了动态代理,AOp的概念。横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ---------- AOP 思想 。
2.
接下来介绍一下Spring框架是怎么实现的AOp的
3.
接下来介绍AOP的相关术语:
4.Aop的底层实现:
Spring AOP 代理实现有两种: JDK动态代理 和 Cglib框架动态代理
JDK API 内置 ---- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理):
JDK API 内置 ---- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )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); }}
因为采用java的动态代理的话必须要求有接口所以为了解决这个问题,提出了Cglib 动态代理。
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理 (解决了 Jdk 只能对接口代理问题 )
下载网址:
------- 在spring3.2版本 core包中内置cglib 类
所以我们可以直接使用,而不需要特意去导入Cglib的包, 我们编写一个Cglib动态代理的程序:
结构图如下:
CglibproxyFactory.java是代理类。CglibProcyTest是Junit的测试类,ProductDAo是被代理的对象。CglibproxyFactory这个代理类仿照前面的java原生代理(JdkProxyFactory )写。
CglibProxyFacory的代码如下:
package b_cglib;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;/* * Create by 沈晓权 * Create on 2016年7月26日下午10:32:55 */public class CglibProxyFactory implements MethodInterceptor{private Object target;/** * */public CglibProxyFactory( Object object) {this.target=object;}//创建代理的方法public Object createProxy(){ //1.创建Enhancer对象 Enhancer enhancer=new Enhancer(); //2.cglib创建代理,对目标对象,创建子类(cglib实现代理是通过子类这种形式创建的) enhancer.setSuperclass(target.getClass()); //3.这一步相当于之前的JdkProxyFactory中的Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); 最后那个this传入 enhancer.setCallback(this);return enhancer.create();}/* (non-Javadoc) * @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], org.springframework.cglib.proxy.MethodProxy) */public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //执行要代理的方法 System.out.print("记录日志"); //执行真正的方法, return method.invoke(target, args);}}
ProductDAo的代码:
//没有接口,就不能使用JDK的动态代理,我们使用public class ProductDAo { public void addProduct() { System.out.print("增加商品"); } public void deleteProduct() { System.out.print("删除商品"); }}
JUnit的代码:
public class CglibProxyTest {@Testpublic void haveproxy(){ //1.创建目标对象 ProductDAo productDAo=new ProductDAo(); //2.创建代理类,因为没有接口所以这里使用ProductDAo proxy这么写的ProductDAo proxy=(ProductDAo)new CglibProxyFactory(productDAo).createProxy();proxy.addProduct();proxy.deleteProduct();}}
Cglib 创建代理思想: 对目标类创建子类对象
设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)
设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )
在cglib的callback函数中,要执行被代理对象的方法
method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args);