Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类.
所以AOP的底层原理实现,实际就是利用动态代理来实现拦截的.
Java代理模式和静态代理
Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理.
设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.
为什么要使用Proxy?
1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.
2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况:
(1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.
(2)如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.
总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系.
下面举例说明:
假设有这样一个接口:
package com.dynamicproxy;
public interface IHello {
/**
* 业务方法
* @param str
*/
void sayHello(String str);
}
我们正常的实现是:
package com.dynamicproxy;
public class Hello implements IHello{
public void sayHello(String str) {
System.out.println("hello "+str);
}
}
那么,我们想要运用代理模式,同时在调用sayHello的时候,前面和后面各打印一条log,怎么实现呢?
我们需要实现一个代理类:
package com.dynamicproxy;
public class ProxyHello implements IHello{
private IHello hello;
public ProxyHello(IHello hello) {
super();
this.hello = hello;
}
public void sayHello(String str) {
Logger.start();//添加特定的方法
hello.sayHello(str);
Logger.end();
}
}
使用的时候,直接用代理类来代理原来的Hello类:
package com.dynamicproxy;
public class Test {
public static void main(String[] args) {
IHello hello = new ProxyHello(new Hello());
hello.sayHello("你好");
}
}
我们实际已经实现了代理模式,但是这是一个静态代理的模式, 试想,我们想要对程序中所有的方法都加类似的log呢,我们是不是需要写无数的这种代理类来实现呢? 那样肯定不好.
动态代理
现在,引入动态代理,只用一个代理类,就实现.
在jdk1.3以后,jdk跟我们提供了一个API java.lang.reflect.InvocationHandler的类, 这个类可以让我们在JVM调用某个类的方法时动态的添加操作.
动态代理实现主要是实现InvocationHandler,并且将目标对象注入到代理对象中,利用反射机制来执行目标对象的方法。
还是基于上面的例子:
我们实现动态代理
package com.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynaProxyHello implements InvocationHandler{
private Object target;//目标对象
/**
* 通过反射来实例化目标对象
* @param object
* @return
*/
public Object bind(Object object){
this.target = object;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
Logger.start();
//通过反射机制来运行目标对象的方法
result = method.invoke(this.target, args);
Logger.end();
return result;
}
}
这样,我们可以动态的代理所有的类:
package com.dynamicproxy;
public class DynaTest {
public static void main(String[] args) {
IHello hello = (IHello) new DynaProxyHello().bind(new Hello());
hello.sayHello("你好");
ICat cat = (ICat) new DynaProxyHello().bind(new Cat());
cat.sayHello("miao");
}
}
快来拷贝代码实际跑一跑吧.