您好,欢迎访问一九零五行业门户网

java 1.8 动态代理源码分析

jdk8动态代理源码分析动态代理的基本使用就不详细介绍了:
例子:
class proxyed implements pro{     @overridepublic void text() {         system.err.println(本方法);     } }interface pro {void text(); }public class javaproxy implements invocationhandler {private object source;public javaproxy(object source) {super();this.source = source;         }public object invoke(object proxy, method method, object[] args) throws throwable {             system.out.println(before);             object invoke = method.invoke(source, args);             system.out.println(after);return invoke;         }public object getproxy(){return proxy.newproxyinstance(getclass().getclassloader(), source.getclass().getinterfaces(), this);         }public static void main(string[] args) throws illegalaccessexception, invocationtargetexception, instantiationexception, nosuchmethodexception {//第一种,自己写//1.设置savegeneratedfiles值为true则生成 class字节码文件方便分析system.getproperties().put(sun.misc.proxygenerator.savegeneratedfiles, true);//2.获取动态代理类class proxyclazz = proxy.getproxyclass(pro.class.getclassloader(),pro.class);//3.获得代理类的构造函数,并传入参数类型invocationhandler.classconstructor constructor = proxyclazz.getconstructor(invocationhandler.class);//4.通过构造函数来创建动态代理对象,将自定义的invocationhandler实例传入pro ihello = (pro) constructor.newinstance(new javaproxy(new proxyed()));//5.通过代理对象调用目标方法            ihello.text();//第二种,调用jdk提供的方法,实现了2~4步proxy.newproxyinstance(javaproxy.class.getclassloader(),proxyed.class.getinterfaces(),new javaproxy(new proxyed()));         } }
入口:newproxyinstancepublic static object newproxyinstance(classloader loader, class<?>[] interfaces, invocationhandler h) throws illegalargumentexception {//objects.requirenonnull 判空方法,之后所有的单纯的判断null并抛异常,都是此方法        objects.requirenonnull(h);//clone 类实现的所有接口final class<?>[] intfs = interfaces.clone();//获取当前系统安全接口final securitymanager sm = system.getsecuritymanager();if (sm != null) {//reflection.getcallerclass返回调用该方法的方法的调用类;loader:接口的类加载器//进行包访问权限、类加载器权限等检查            checkproxyaccess(reflection.getcallerclass(), loader, intfs);         }/* * look up or generate the designated proxy class.          *  查找或生成代理类         */class<?> cl = getproxyclass0(loader, intfs);/* * invoke its constructor with the designated invocation handler.          * 使用指定的调用处理程序调用它的构造函数         */try {if (sm != null) {                 checknewproxypermission(reflection.getcallerclass(), cl);             }//获取构造final constructor<?> cons = cl.getconstructor(constructorparams);final invocationhandler ih = h;if (!modifier.ispublic(cl.getmodifiers())) {                 accesscontroller.doprivileged(new privilegedaction<void>() {public void run() {                         cons.setaccessible(true);return null;                     }                 });             }//返回 代理对象return cons.newinstance(new object[]{h});         } catch (illegalaccessexception|instantiationexception e) {throw new internalerror(e.tostring(), e);         } catch (invocationtargetexception e) {             throwable t = e.getcause();if (t instanceof runtimeexception) {throw (runtimeexception) t;             } else {throw new internalerror(t.tostring(), t);             }         } catch (nosuchmethodexception e) {throw new internalerror(e.tostring(), e);         }     }
从上面的分析中可以看出,newproxyinstance帮我们执行了生成代理类----获取构造器----生成代理对象这三步;
我们重点分析生成代理类
getproxyclass0/** * a cache of proxy classes:动态代理类的弱缓存容器      * keyfactory:根据接口的数量,映射一个最佳的key生成函数,其中表示接口的类对象被弱引用;也就是key对象被弱引用继承自weakreference(key0、key1、key2、keyx),保存接口密钥(hash值)      * proxyclassfactory:生成动态类的工厂      * 注意,两个都实现了bifunction接口     */private static final weakcache proxyclasscache = new weakcache<>(new keyfactory(), new proxyclassfactory());/** * generate a proxy class.  must call the checkproxyaccess method      * to perform permission checks before calling this.      * 生成代理类,调用前必须进行 checkproxyaccess权限检查,所以newproxyinstance进行了权限检查     */private static class<?> getproxyclass0(classloader loader, class<?>... interfaces) {//实现接口的最大数量<65535;谁写的类能实现这么多接口if (interfaces.length > 65535) {throw new illegalargumentexception(interface limit exceeded);         }// if the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the proxyclassfactory// 如果缓存中有,就直接返回,否则会生成return proxyclasscache.get(loader, interfaces);     }
proxyclasscache.getpublic v get(k key, p parameter) {//key:类加载器;parameter:接口数组        objects.requirenonnull(parameter);//清除已经被gc回收的弱引用        expungestaleentries();//cachekey弱引用类,refqueue已经被回收的弱引用队列;构建一个cachekeyobject cachekey = cachekey.valueof(key, refqueue);        //map一级缓存,获取valuesmap二级缓存concurrentmap<object, supplier<v>> valuesmap = map.get(cachekey);if (valuesmap == null) {             concurrentmap<object, supplier<v>> oldvaluesmap= map.putifabsent(cachekey,                     valuesmap = new concurrenthashmap<>());if (oldvaluesmap != null) {                 valuesmap = oldvaluesmap;             }         }// subkeyfactory类型是keyfactory,apply返回表示接口的keyobject subkey = objects.requirenonnull(subkeyfactory.apply(key, parameter));//factory 实现了supplier,我们实际是获取缓存中的factory,调用其get方法supplier<v> supplier = valuesmap.get(subkey);         factory factory = null;        //下面用到了 cas+重试 实现的多线程安全的 非阻塞算法while (true) {if (supplier != null) {// 只需要知道,最终会调用get方法,此supplier可能是缓存中取出来的,也可能是factory新new出来的v value = supplier.get();if (value != null) {return value;                 }             }// else no supplier in cache// or a supplier that returned null (could be a cleared cachevalue// or a factory that wasn't successful in installing the cachevalue)// lazily construct a factoryif (factory == null) {                 factory = new factory(key, parameter, subkey, valuesmap);             }if (supplier == null) {                 supplier = valuesmap.putifabsent(subkey, factory);if (supplier == null) {// successfully installed factorysupplier = factory;                 }// else retry with winning supplier} else {if (valuesmap.replace(subkey, supplier, factory)) {// successfully replaced// cleared cacheentry / unsuccessful factory// with our factorysupplier = factory;                 } else {// retry with current suppliersupplier = valuesmap.get(subkey);                 }             }         }     }
supplier.get这个方法中会调用proxyclassfactory的apply方法,就不过多介绍
proxyclassfactory.applypublic class<?> apply(classloader loader, class<?>[] interfaces) {         map interfaceset = new identityhashmap<>(interfaces.length);for (class<?> intf : interfaces) {/* * verify that the class loader resolves the name of this interface to the same class object.                  * 类加载器和接口名解析出的是同一个                 */class<?> interfaceclass = null;try {                 interfaceclass = class.forname(intf.getname(), false, loader);             } catch (classnotfoundexception e) {             }if (interfaceclass != intf) {throw new illegalargumentexception( intf +  is not visible from class loader);             }/* * verify that the class object actually represents an interface.                  * 确保是一个接口                 */if (!interfaceclass.isinterface()) {throw new illegalargumentexception( interfaceclass.getname() +  is not an interface);             }/* * verify that this interface is not a duplicate.                  * 确保接口没重复                 */if (interfaceset.put(interfaceclass, boolean.true) != null) {throw new illegalargumentexception( repeated interface:  + interfaceclass.getname());             }         }         string proxypkg = null;     // package to define proxy class inint accessflags = modifier.public | modifier.final;/* * record the package of a non-public proxy interface so that the proxy class will be defined in the same package.              * verify that all non-public proxy interfaces are in the same package.              * 验证所有非公共的接口在同一个包内;公共的就无需处理             */for (class<?> intf : interfaces) {int flags = intf.getmodifiers();if (!modifier.ispublic(flags)) {                 accessflags = modifier.final;                 string name = intf.getname();int n = name.lastindexof('.');                 string pkg = ((n == -1) ?  : name.substring(0, n + 1));if (proxypkg == null) {                     proxypkg = pkg;                 } else if (!pkg.equals(proxypkg)) {throw new illegalargumentexception(  non-public interfaces from different packages);                 }             }         }if (proxypkg == null) {// if no non-public proxy interfaces, use com.sun.proxy packageproxypkg = reflectutil.proxy_package + .;         }/* * choose a name for the proxy class to generate.              * proxyclassnameprefix = $proxy              * nextuniquenumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$proxy0,$proxy1......             */long num = nextuniquenumber.getandincrement();         string proxyname = proxypkg + proxyclassnameprefix + num;/* * generate the specified proxy class.              * 生成类字节码的方法:重点             */byte[] proxyclassfile = proxygenerator.generateproxyclass( proxyname, interfaces, accessflags);try {return defineclass0(loader, proxyname, proxyclassfile, 0, proxyclassfile.length);         } catch (classformaterror e) {/* * a classformaterror here means that (barring bugs in the                  * proxy class generation code) there was some other                  * invalid aspect of the arguments supplied to the proxy                  * class creation (such as virtual machine limitations                  * exceeded).                 */throw new illegalargumentexception(e.tostring());         }     }
proxygenerator.generateproxyclasspublic static byte[] generateproxyclass(final string name, class<?>[] interfaces, int accessflags) {         proxygenerator gen = new proxygenerator(name, interfaces, accessflags);//真正生成字节码的方法final byte[] classfile = gen.generateclassfile();//如果savegeneratedfiles为true 则生成字节码文件,所以在开始我们要设置这个参数//当然,也可以通过返回的bytes自己输出if (savegeneratedfiles) {             java.security.accesscontroller.doprivileged( new java.security.privilegedaction<void>() {public void run() {try {int i = name.lastindexof('.');                                 path path;if (i > 0) {                                     path dir = paths.get(name.substring(0, i).replace('.', file.separatorchar));                                     files.createdirectories(dir);                                     path = dir.resolve(name.substring(i+1, name.length()) + .class);                                 } else {                                     path = paths.get(name + .class);                                 }                                 files.write(path, classfile);return null;                             } catch (ioexception e) {throw new internalerror( i/o exception saving generated file:  + e);                             }                         }                     });         }return classfile;     }
最终方法
private byte[] generateclassfile() {/* ============================================================          * step 1: assemble proxymethod objects for all methods to generate proxy dispatching code for.          * 步骤1:为所有方法生成代理调度代码,将代理方法对象集合起来。         *///增加 hashcode、equals、tostring方法addproxymethod(hashcodemethod, object.class);         addproxymethod(equalsmethod, object.class);         addproxymethod(tostringmethod, object.class);//增加接口方法for (class<?> intf : interfaces) {for (method m : intf.getmethods()) {                 addproxymethod(m, intf);             }         }/* * 验证方法签名相同的一组方法,返回值类型是否相同;意思就是重写方法要方法签名和返回值一样         */for (list<proxymethod> sigmethods : proxymethods.values()) {             checkreturntypes(sigmethods);         }/* ============================================================          * step 2: assemble fieldinfo and methodinfo structs for all of fields and methods in the class we are generating.          * 为类中的方法生成字段信息和方法信息         */try {//增加构造方法            methods.add(generateconstructor());for (list<proxymethod> sigmethods : proxymethods.values()) {for (proxymethod pm : sigmethods) {// add static field for method's method objectfields.add(new fieldinfo(pm.methodfieldname,ljava/lang/reflect/method;,                             acc_private | acc_static));// generate code for proxy method and add it                    methods.add(pm.generatemethod());                 }             }//增加静态初始化信息            methods.add(generatestaticinitializer());         } catch (ioexception e) {throw new internalerror(unexpected i/o exception, e);         }if (methods.size() > 65535) {throw new illegalargumentexception(method limit exceeded);         }if (fields.size() > 65535) {throw new illegalargumentexception(field limit exceeded);         }/* ============================================================          * step 3: write the final class file.          * 步骤3:编写最终类文件         *//* * make sure that constant pool indexes are reserved for the following items before starting to write the final class file.          * 在开始编写最终类文件之前,确保为下面的项目保留常量池索引。         */cp.getclass(dottoslash(classname));         cp.getclass(superclassname);for (class<?> intf: interfaces) {             cp.getclass(dottoslash(intf.getname()));         }/* * disallow new constant pool additions beyond this point, since we are about to write the final constant pool table.          * 设置只读,在这之前不允许在常量池中增加信息,因为要写常量池表         */cp.setreadonly();         bytearrayoutputstream bout = new bytearrayoutputstream();         dataoutputstream dout = new dataoutputstream(bout);try {// u4 magic;dout.writeint(0xcafebabe);// u2 次要版本;            dout.writeshort(classfile_minor_version);// u2 主版本            dout.writeshort(classfile_major_version);             cp.write(dout);             // (write constant pool)// u2 访问标识;            dout.writeshort(accessflags);// u2 本类名;            dout.writeshort(cp.getclass(dottoslash(classname)));// u2 父类名;            dout.writeshort(cp.getclass(superclassname));// u2 接口;            dout.writeshort(interfaces.length);// u2 interfaces[interfaces_count];for (class<?> intf : interfaces) {                 dout.writeshort(cp.getclass(                         dottoslash(intf.getname())));             }// u2 字段;            dout.writeshort(fields.size());// field_info fields[fields_count];for (fieldinfo f : fields) {                 f.write(dout);             }// u2 方法;            dout.writeshort(methods.size());// method_info methods[methods_count];for (methodinfo m : methods) {                 m.write(dout);             }// u2 类文件属性:对于代理类来说没有类文件属性;dout.writeshort(0); // (no classfile attributes for proxy classes)} catch (ioexception e) {throw new internalerror(unexpected i/o exception, e);         }return bout.tobytearray();     }
生成的字节码反编译
final class $proxy0 extends proxy implements pro {//fields    private static method m1;private static method m2;private static method m3;private static method m0;public $proxy0(invocationhandler var1) throws  {super(var1);         }public final boolean equals(object var1) throws  {try {return ((boolean)super.h.invoke(this, m1, new object[]{var1})).booleanvalue();             } catch (runtimeexception | error var3) {throw var3;             } catch (throwable var4) {throw new undeclaredthrowableexception(var4);             }         }public final string tostring() throws  {try {return (string)super.h.invoke(this, m2, (object[])null);             } catch (runtimeexception | error var2) {throw var2;             } catch (throwable var3) {throw new undeclaredthrowableexception(var3);             }         }public final void text() throws  {try {//实际就是调用代理类的invoke方法 super.h.invoke(this, m3, (object[])null);             } catch (runtimeexception | error var2) {throw var2;             } catch (throwable var3) {throw new undeclaredthrowableexception(var3);             }         }public final int hashcode() throws  {try {return ((integer)super.h.invoke(this, m0, (object[])null)).intvalue();             } catch (runtimeexception | error var2) {throw var2;             } catch (throwable var3) {throw new undeclaredthrowableexception(var3);             }         }static {try {//这里每个方法对象 和类的实际方法绑定m1 = class.forname(java.lang.object).getmethod(equals, new class[]{class.forname(java.lang.object)});                 m2 = class.forname(java.lang.object).getmethod(tostring, new class[0]);                 m3 = class.forname(spring.commons.api.study.createmodel.pro).getmethod(text, new class[0]);                 m0 = class.forname(java.lang.object).getmethod(hashcode, new class[0]);             } catch (nosuchmethodexception var2) {throw new nosuchmethoderror(var2.getmessage());             } catch (classnotfoundexception var3) {throw new noclassdeffounderror(var3.getmessage());             }         }     }
以上就是java 1.8 动态代理源码分析的详细内容。
其它类似信息

推荐信息