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 动态代理源码分析的详细内容。