java 1.8 动态代理源码深度分析
程序员文章站
2023-12-19 17:34:04
jdk8动态代理源码分析
动态代理的基本使用就不详细介绍了:
例子:
class proxyed implements pro{
@override...
jdk8动态代理源码分析
动态代理的基本使用就不详细介绍了:
例子:
class proxyed implements pro{ @override public 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.class constructor 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())); } }
入口:newproxyinstance
public 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<classloader, class<?>[], object>接口 */ private static final weakcache<classloader, class<?>[], class<?>> 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.get
public v get(k key, p parameter) { //key:类加载器;parameter:接口数组 objects.requirenonnull(parameter); //清除已经被gc回收的弱引用 expungestaleentries(); //cachekey弱引用类,refqueue已经被回收的弱引用队列;构建一个cachekey object 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返回表示接口的key object 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 factory if (factory == null) { factory = new factory(key, parameter, subkey, valuesmap); } if (supplier == null) { supplier = valuesmap.putifabsent(subkey, factory); if (supplier == null) { // successfully installed factory supplier = factory; } // else retry with winning supplier } else { if (valuesmap.replace(subkey, supplier, factory)) { // successfully replaced // cleared cacheentry / unsuccessful factory // with our factory supplier = factory; } else { // retry with current supplier supplier = valuesmap.get(subkey); } } } }
supplier.get
这个方法中会调用proxyclassfactory的apply方法,就不过多介绍
proxyclassfactory.apply
public class<?> apply(classloader loader, class<?>[] interfaces) { map<class<?>, boolean> 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 in int 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 package proxypkg = 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.generateproxyclass
public 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 object fields.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 动态代理源码深度分析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。