彻底理解JAVA动态代理
本文内容纲要:
-代理设计模式
-动态代理使用
-动态代理内部实现
-总结
-美中不足
-参考资料
代理设计模式
定义:为其他对象提供一种代理以控制对这个对象的访问。
代理模式的结构如下图所示。
动态代理使用
java动态代理机制以巧妙的方式实现了代理模式的设计理念。
代理模式示例代码
publicinterfaceSubject
{
publicvoiddoSomething();
}
publicclassRealSubjectimplementsSubject
{
publicvoiddoSomething()
{
System.out.println("calldoSomething()");
}
}
publicclassProxyHandlerimplementsInvocationHandler
{
privateObjectproxied;
publicProxyHandler(Objectproxied)
{
this.proxied=proxied;
}
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable
{
//在转调具体目标对象之前,可以执行一些功能处理
//转调具体目标对象的方法
returnmethod.invoke(proxied,args);
//在转调具体目标对象之后,可以执行一些功能处理
}
}
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
importsun.misc.ProxyGenerator;
importjava.io.*;
publicclassDynamicProxy
{
publicstaticvoidmain(Stringargs[])
{
RealSubjectreal=newRealSubject();
SubjectproxySubject=(Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
newClass[]{Subject.class},
newProxyHandler(real));
proxySubject.doSomething();
//writeproxySubjectclassbinarydatatofile
createProxyClassFile();
}
publicstaticvoidcreateProxyClassFile()
{
Stringname="ProxySubject";
byte[]data=ProxyGenerator.generateProxyClass(name,newClass[]{Subject.class});
try
{
FileOutputStreamout=newFileOutputStream(name+".class");
out.write(data);
out.close();
}
catch(Exceptione)
{
e.printStackTrace();
}
}
}
动态代理内部实现
首先来看看类Proxy的代码实现Proxy的主要静态变量
//映射表:用于维护类装载器对象到其对应的代理类缓存
privatestaticMaploaderToCache=newWeakHashMap();
//标记:用于标记一个动态代理类正在被创建中
privatestaticObjectpendingGenerationMarker=newObject();
//同步表:记录已经被创建的动态代理类类型,主要被方法isProxyClass进行相关的判断
privatestaticMapproxyClasses=Collections.synchronizedMap(newWeakHashMap());
//关联的调用处理器引用
protectedInvocationHandlerh;
Proxy的构造方法
//由于Proxy内部从不直接调用构造函数,所以private类型意味着禁止任何调用
privateProxy(){}
//由于Proxy内部从不直接调用构造函数,所以protected意味着只有子类可以调用
protectedProxy(InvocationHandlerh){this.h=h;}
Proxy静态方法newProxyInstance
publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException{
//检查h不为空,否则抛异常
if(h==null){
thrownewNullPointerException();
}
//获得与指定类装载器和一组接口相关的代理类类型对象
Classcl=getProxyClass(loader,interfaces);
//通过反射获取构造函数对象并生成代理类实例
try{
Constructorcons=cl.getConstructor(constructorParams);
return(Object)cons.newInstance(newObject[]{h});
}catch(NoSuchMethodExceptione){thrownewInternalError(e.toString());
}catch(IllegalAccessExceptione){thrownewInternalError(e.toString());
}catch(InstantiationExceptione){thrownewInternalError(e.toString());
}catch(InvocationTargetExceptione){thrownewInternalError(e.toString());
}
}
类Proxy的getProxyClass方法调用ProxyGenerator的generateProxyClass方法产生ProxySubject.class的二进制数据:
publicstaticbyte[]generateProxyClass(finalStringname,Class[]interfaces)
我们可以importsun.misc.ProxyGenerator,调用generateProxyClass方法产生binarydata,然后写入文件,最后通过反编译工具来查看内部实现原理。反编译后的ProxySubject.javaProxy静态方法newProxyInstance
importjava.lang.reflect.*;
publicfinalclassProxySubjectextendsProxy
implementsSubject
{
privatestaticMethodm1;
privatestaticMethodm0;
privatestaticMethodm3;
privatestaticMethodm2;
publicProxySubject(InvocationHandlerinvocationhandler)
{
super(invocationhandler);
}
publicfinalbooleanequals(Objectobj)
{
try
{
return((Boolean)super.h.invoke(this,m1,newObject[]{
obj
})).booleanValue();
}
catch(Error_ex){}
catch(Throwablethrowable)
{
thrownewUndeclaredThrowableException(throwable);
}
}
publicfinalinthashCode()
{
try
{
return((Integer)super.h.invoke(this,m0,null)).intValue();
}
catch(Error_ex){}
catch(Throwablethrowable)
{
thrownewUndeclaredThrowableException(throwable);
}
}
publicfinalvoiddoSomething()
{
try
{
super.h.invoke(this,m3,null);
return;
}
catch(Error_ex){}
catch(Throwablethrowable)
{
thrownewUndeclaredThrowableException(throwable);
}
}
publicfinalStringtoString()
{
try
{
return(String)super.h.invoke(this,m2,null);
}
catch(Error_ex){}
catch(Throwablethrowable)
{
thrownewUndeclaredThrowableException(throwable);
}
}
static
{
try
{
m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{
Class.forName("java.lang.Object")
});
m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);
m3=Class.forName("Subject").getMethod("doSomething",newClass[0]);
m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);
}
catch(NoSuchMethodExceptionnosuchmethodexception)
{
thrownewNoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundExceptionclassnotfoundexception)
{
thrownewNoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
ProxyGenerator内部是如何生成class二进制数据,可以参考源代码。
privatebyte[]generateClassFile(){
/*
*RecordthatproxymethodsareneededforthehashCode,equals,
*andtoStringmethodsofjava.lang.Object.Thisisdonebefore
*themethodsfromtheproxyinterfacessothatthemethodsfrom
*java.lang.Objecttakeprecedenceoverduplicatemethodsinthe
*proxyinterfaces.
*/
addProxyMethod(hashCodeMethod,Object.class);
addProxyMethod(equalsMethod,Object.class);
addProxyMethod(toStringMethod,Object.class);
/*
*Nowrecordallofthemethodsfromtheproxyinterfaces,giving
*earlierinterfacesprecedenceoverlateroneswithduplicate
*methods.
*/
for(inti=0;i<interfaces.length;i++){
Method[]methods=interfaces[i].getMethods();
for(intj=0;j<methods.length;j++){
addProxyMethod(methods[j],interfaces[i]);
}
}
/*
*Foreachsetofproxymethodswiththesamesignature,
*verifythatthemethods'returntypesarecompatible.
*/
for(List<ProxyMethod>sigmethods:proxyMethods.values()){
checkReturnTypes(sigmethods);
}
/*============================================================
*Step2:AssembleFieldInfoandMethodInfostructsforallof
*fieldsandmethodsintheclasswearegenerating.
*/
try{
methods.add(generateConstructor());
for(List<ProxyMethod>sigmethods:proxyMethods.values()){
for(ProxyMethodpm:sigmethods){
//addstaticfieldformethod'sMethodobject
fields.add(newFieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE|ACC_STATIC));
//generatecodeforproxymethodandaddit
methods.add(pm.generateMethod());
}
}
methods.add(generateStaticInitializer());
}catch(IOExceptione){
thrownewInternalError("unexpectedI/OException");
}
/*============================================================
*Step3:Writethefinalclassfile.
*/
/*
*Makesurethatconstantpoolindexesarereservedforthe
*followingitemsbeforestartingtowritethefinalclassfile.
*/
cp.getClass(dotToSlash(className));
cp.getClass(superclassName);
for(inti=0;i<interfaces.length;i++){
cp.getClass(dotToSlash(interfaces[i].getName()));
}
/*
*Disallownewconstantpooladditionsbeyondthispoint,since
*weareabouttowritethefinalconstantpooltable.
*/
cp.setReadOnly();
ByteArrayOutputStreambout=newByteArrayOutputStream();
DataOutputStreamdout=newDataOutputStream(bout);
try{
/*
*Writealltheitemsofthe"ClassFile"structure.
*SeeJVMSsection4.1.
*/
//u4magic;
dout.writeInt(0xCAFEBABE);
//u2minor_version;
dout.writeShort(CLASSFILE_MINOR_VERSION);
//u2major_version;
dout.writeShort(CLASSFILE_MAJOR_VERSION);
cp.write(dout);//(writeconstantpool)
//u2access_flags;
dout.writeShort(ACC_PUBLIC|ACC_FINAL|ACC_SUPER);
//u2this_class;
dout.writeShort(cp.getClass(dotToSlash(className)));
//u2super_class;
dout.writeShort(cp.getClass(superclassName));
//u2interfaces_count;
dout.writeShort(interfaces.length);
//u2interfaces[interfaces_count];
for(inti=0;i<interfaces.length;i++){
dout.writeShort(cp.getClass(
dotToSlash(interfaces[i].getName())));
}
//u2fields_count;
dout.writeShort(fields.size());
//field_infofields[fields_count];
for(FieldInfof:fields){
f.write(dout);
}
//u2methods_count;
dout.writeShort(methods.size());
//method_infomethods[methods_count];
for(MethodInfom:methods){
m.write(dout);
}
//u2attributes_count;
dout.writeShort(0);//(noClassFileattributesforproxyclasses)
}catch(IOExceptione){
thrownewInternalError("unexpectedI/OException");
}
returnbout.toByteArray();
总结
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器IvocationHandlerhandler=newInvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Classclazz=Proxy.getProxyClass(classLoader,newClass[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructorconstructor=clazz.getConstructor(newClass[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
InterfaceProxy=(Interface)constructor.newInstance(newObject[](handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Objectresult=method.invoke(proxied,args))
美中不足
诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。
参考资料
1、JDK动态代理实现原理
2、Java动态代理机制分析及扩展
本文内容总结:代理设计模式,动态代理使用,动态代理内部实现,总结,美中不足,参考资料,
原文链接:https://www.cnblogs.com/flyoung2008/p/3251148.html