深入理解java动态代理的两种实现方式(JDK/Cglib)
什么是代理模式?
代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。
为什么要使用代理模式?
通过代理模式可以实现对目标类调用的控制、在目标类调用前/后进行一些不属于目标类的操作,如:数据验证、预处理、后处理、异常处理等
什么是静态代理什么是动态代理?
- 静态代理:代理类只能实现对”特定接口的实现类“进行代理
- 动态代理:代理类可以实现对多种类的代理
jdk代理和cglib代理区别在哪里?
- jdk动态代理:代理所有“实现的有接口”的目标类
- cglib动态代理:代理任意一个目标类,但对final类和方法无法代理
不同点:jdk动态代理的目标类必须实现的有接口,因为在调用Proxy.newProxyInstance()的时候需要传入目标类的接口类。而cglib不做此限制。
下面看代码分析:
定义一个Person接口
packagecom.zpj.designMode.proxy;
//定义一个Person接口
publicinterfacePerson{
publicvoiddoWork();
}
添加一个实现类:MrLi
packagecom.zpj.designMode.proxy;
//添加一个实现类
publicclassMrLiimplementsPerson{
@Override
publicvoiddoWork(){
System.out.println("-----doWork");
}
}
静态代理:
添加一个静态代理类Proxy
packagecom.zpj.designMode.proxy;
//静态代理,代理必须和目标类实现共同的接口
publicclassProxyimplementsPerson{
privatePersonperson;//被代理人
//这里的目标类型决定了该代理类只能代理实现了Person接口的实例,而不能接收其他类型参数,这也就是静态代理的局限性
publicProxy(Personperson){
this.person=person;
}
@Override
publicvoiddoWork(){
System.out.println("doSomething-----start");
person.doWork();
System.out.println("doSomething-----end");
}
}
静态代理测试程序:
packagecom.zpj.designMode.proxy;
publicclassRun{
publicstaticvoidmain(String[]args){
MrLili=newMrLi();
Proxyproxy=newProxy(li);
//调用处直接调用代理进行目标方法的操作。
proxy.doWork();
}
}
JDK动态代理:
添加一个代理JDKProxy,该代理实现InvocationHandler接口且覆写invoke方法。
packagecom.zpj.designMode.proxy.jdk;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
/***
@authorPerkinsZhu
@date2017年3月13日上午8:41:10
*/
publicclassJDKProxyimplementsInvocationHandler{
privateObjectperson;//被代理人
//这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理。但是要注意下面的newProxyInstance()中的参数
publicObjectgetInstance(Objectperson){
this.person=person;
//与cglib的区别在于这里构建代理对象的时候需要传入被代理对象的接口对象,第二个参数。而cglib不需要被代理对象实现任何接口即可
returnProxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),this);
}
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
System.out.println("doSomething---------start");
method.invoke(person,args);
System.out.println("doSomething---------end");
returnnull;
}
}
JDK动态代理测试程序
packagecom.zpj.designMode.proxy.jdk;
importcom.zpj.designMode.proxy.MrLi;
importcom.zpj.designMode.proxy.Person;
/***
*@authorPerkinsZhu
*@date2017年3月13日上午8:51:31
*/
publicclassRun{
publicstaticvoidmain(String[]args){
Personperson=(Person)newJDKProxy().getInstance(newMrLi());
//注意这里的person不是目标类person,而是代理类person:debug的时候显示null,有'$'标识符
person.doWork();
}
}
Cglib动态代理:
添加一个CglibProxy代理,同时实现MethodInterceptor接口。
packagecom.zpj.designMode.proxy.cglib;
importjava.lang.reflect.Method;
importnet.sf.cglib.proxy.Enhancer;
importnet.sf.cglib.proxy.MethodInterceptor;
importnet.sf.cglib.proxy.MethodProxy;
/***
*@authorPerkinsZhu
*@date2017年3月13日上午9:02:54
*/
publicclassCglibProxyimplementsMethodInterceptor{
privateObjecttargetObject;
//这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
publicObjectgetInstance(Objecttarget){
this.targetObject=target;
Enhancerenhancer=newEnhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//注意该处代理的创建过程
ObjectproxyObj=enhancer.create();
returnproxyObj;//返回代理对象
}
@Override
publicObjectintercept(Objectproxy,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{
Objectobj=null;
System.out.println("doSomething---------start");
obj=method.invoke(targetObject,args);
System.out.println("doSomething---------end");
returnobj;
}
}
Cglib动态代理测试程序
packagecom.zpj.designMode.proxy.cglib;
importcom.zpj.designMode.proxy.MrLi;
importcom.zpj.designMode.proxy.Person;
/***
@authorPerkinsZhu
@date2017年3月13日上午9:07:38
*/
publicclassRun{
publicstaticvoidmain(String[]args){
Personperson=(Person)newCglibProxy().getInstance(newMrLi());
person.doWork();
}
}
仔细对比Proxy、CglibProxy和JDKProxy区分静态代理、JDK动态代理和Cglib动态代理的异同点!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。