设计模式(1-4)-动态代理(ProxyGenerator)
前面讲的都是一些代理类生成的一些准备工作,本节讲讲代理类如何生成出来的一个过程。
java.lang.reflect.Proxy.ProxyClassFactory#apply
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
...
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
...
}
sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[], int)
public static byte[] generateProxyClass(final String name,
Class<?>[] interfaces,
int accessFlags)
{
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
// !!!! 生成代理类的字节码文件
final byte[] classFile = gen.generateClassFile();
// 保存代理类的class文件 👇
// 这样设置就可以保存了,System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
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;
}
代理类的具体实现就在sun.misc.ProxyGenerator#generateClassFile
, 我们来看看它的源码
一、generateClassFile
sun.misc.ProxyGenerator#generateClassFile
,根据源码中的注释,我们把源码分成三部
步骤一: 为所有方法组装ProxyMethod对象;检查相同签名(方法名 + 参数列表)的代理方法,其返回类型是否兼容
private byte[] generateClassFile() {
// Obeject的hashcode、equals,toString添加到proxyMethods中,以便代理类中存在这些方法。
// 它比代理接口中的方法先完成,这样可以保证代理类的方法能重写这三个方法
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);
}
....
}
步骤二: 为所有fields和methods组装对应的结构
private byte[] generateClassFile() {
...
try {
// 为代理类生成构造器
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 添加方法的Method对象的静态字段, eg, private static Method m1;
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// 为代理类生成代码并添加它
methods.add(pm.generateMethod());
}
}
// 为代理类生成初始化方法
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
// JVM的规定!
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
...
}
步骤三: Write the final class file.!
private byte[] generateClassFile() {
...
// 保证下面的这些东西要存在常量池的索引中,在开始写类文件之前
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 {
/*
* Write all the items of the "ClassFile" structure.
* See JVMS section 4.1.
*/
// u4 magic;
dout.writeInt(0xCAFEBABE);
// u2 minor_version;
dout.writeShort(CLASSFILE_MINOR_VERSION);
// u2 major_version;
dout.writeShort(CLASSFILE_MAJOR_VERSION);
cp.write(dout); // (write constant pool)
// u2 access_flags;
dout.writeShort(accessFlags);
// u2 this_class;
dout.writeShort(cp.getClass(dotToSlash(className)));
// u2 super_class;
dout.writeShort(cp.getClass(superclassName));
// u2 interfaces_count;
dout.writeShort(interfaces.length);
// u2 interfaces[interfaces_count];
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
// u2 fields_count;
dout.writeShort(fields.size());
// field_info fields[fields_count];
for (FieldInfo f : fields) {
f.write(dout);
}
// u2 methods_count;
dout.writeShort(methods.size());
// method_info methods[methods_count];
for (MethodInfo m : methods) {
m.write(dout);
}
// u2 attributes_count;
dout.writeShort(0); // (no ClassFile attributes for proxy classes)
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray();
...
}
在try
中的代码,是在写ClassFile(字节码)的结构, 可以参考Chapter 4. The class File Format
上面我们看了代理类的字节码的生成,我们现在再看一看生成的代理类(修改了少量地方),是不是有不一样的感觉了。
// 生成的代理类继承了Proxy
public final class Proxy0 extends Proxy implements UpanSell {
// Method的静态字段
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
// 构造器
public Proxy0(InvocationHandler var1) {
super(var1);
}
// 为代理类生成的方法 👇-------
@Override
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
@Override
public final String toString() {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
@Override
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
@Override
public final float sell(int var1) {
try {
return (Float)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.ukyu.dynamicproxy.service.UpanSell").getMethod("sell", Integer.TYPE);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
我们将
UpanSell proxy = (UpanSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler
);
改为 ->
UpanSell proxy = new Proxy0(handler);
输出的效果是一样的。
二、总结
我们将具体生成代理类的过程走了一遍,结合源码食用更佳
tips: 只能给实现了接口的类,使用JDK动态代理来创建代理类
若想给没有实现接口的类,动态生成代理类,就需要使用CGLIB,可以参考一下CGLib动态代理这篇博客
三、引用
有疑问或者博客内容存在错误,请告诉我,谢谢啦