由于工作的原因好久没有写博客了,再次写博,目的有两,一、“烂笔头胜过最好的记忆”,所以想把自己觉得有价值的东西写下来,以便以后查阅;二、希望能遇见志同道合的朋友,将知识进行共享,讨论,使自己的技术水平有更大的提高。
废话少说,言归正传,动态代理应该算java的核心技术,Spring的AOP的底层实现用了,hibernate的接口实现也用了,由此可见动态代理至于java确实非常重要,那么今天就来讨论一下动态代理。java中的动态代理大家接触最多的应该是:JDK 的动态代理和CGLIB动态代理。我将从以下几个方面讨论这个问题:
1、两者区别
2、详细介绍JDK动态代理
3、详细介绍CGLIB动态代理
4、两者的性能对比
首先讨论区别:
还是以程序员习惯的代码出发进行讨论:
1.JDK的动态代理
接口:
public interface Helloworld {
String say(String name);//在这里我还是用大家熟悉的helloworld作为演示示例
}
接口实现类:
public class HelloworldImp implements Helloworld{
@Override
public String say(String name) {
return "hello:"+name;
}
}
代理实例的调用处理程序 实现的接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class HelloworldHandler implements InvocationHandler {
private Object methodProxy;
public HelloworldHandler(Object methodProxy) {
this.methodProxy = methodProxy;//需要代理的对象,在这个例子中就是helloWorldImp
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result;
System.out.println("Before Helloworld");
result=method.invoke(methodProxy, args);//执行代理对象的方法
System.out.println("After HelloWorld");
return result;
}
}
测试代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Date;
public class TestJdk {
/**
* @param args
*/
public static void main(String[] args) {
HelloworldImp helloWorldImp=new HelloworldImp();
InvocationHandler invocationHandler=new HelloworldHandler(helloWorldImp);
Helloworld helloWorld=(Helloworld) Proxy.newProxyInstance(helloWorldImp.getClass().getClassLoader(),helloWorldImp.getClass().getInterfaces(),invocationHandler);
Date startDate=new Date();
helloWorld.say("柯磊");
Date endDate=new Date();
System.out.println("用时:"+(endDate.getTime()-startDate.getTime()));
}
}
2.CGLIB动态代理
为了更好的对比两者,在这里使用一样的HelloworldImp,但是提醒一下,Helloworld接口不是必须的。
public class HelloworldImp implements Helloworld{
@Override
public String say(String name) {
// TODO Auto-generated method stub
return "hello:"+name;
}
}
代理类:
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class HelloworldProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object result;
System.out.println("Before Helloworld");
result=methodProxy.invokeSuper(obj, args);
System.out.println("After HelloWorld");
return result;
}
}
测试代码:
import javax.xml.crypto.Data;
import net.sf.cglib.proxy.Enhancer;
public class TestCglib {
/**
* @param args
*/
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(HelloworldImp.class);
enhancer.setCallback(new HelloworldProxy());
HelloworldImp helloWorld=(HelloworldImp) enhancer.create();
Date startDate=new Date();
helloWorld.say("柯磊");
Date endDate=new Date();
System.out.println("用时:"+(endDate.getTime()-startDate.getTime()));
}
}
通过上面的代码我们能很清楚看出二者的区别:
1、JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理
2、CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时,也可以通过 CGLIB 来实现代理
今天就写到这,后续会为大家进行更深入的介绍。