JDK动态代理
1.动态代理
代理模式一般用于增强类的方法而不直接修改原始类的代码,动态代理可以用于动态生成目标类的代理类来执行相应操作,目前动态代理主要有JDK动态代理以及CGLIB,经常会提起,也会看一下解释,但是并没有真正实践过,现在学习一下。
JDK动态代理,使用反射机制,一般用来代理接口类。
具体来说
1.要有目标接口
目标接口实现类
2.实现InvocationHandler,进行目标方法的增强
3.调用Proxy.newProxyInstance, 产生动态代理类,执行方法
第一种调用代理类的方式
首先获取代理类,获得代理类的构造函数,通过构造函数来生成动态代理对象,调用动态对象目标方法
第二种调用方式Proxy直接对以上操作进行了封装
此外,我们使用ProxyGenerator来生成动态代理类并保存class文件,以便进行反编译分析,项目中导入ProxyGenerator类,进行字节码的生成
2.动态代理类的分析:
反编译Proxy0.class文件如下所示:
import com.sun.proxy..Proxy0;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Proxy0 {
private static Method m1;
private static Method m6;
private static Method m2;
private static Method m7;
private static Method m11;
private static Method m13;
private static Method m0;
private static Method m8;
private static Method m3;
private static Method m12;
private static Method m5;
private static Method m10;
private static Method m4;
private static Method m9;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final InvocationHandler getInvocationHandler(Object var1) throws IllegalArgumentException {
try {
return (InvocationHandler) super.h.invoke(this, m6, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final Class getProxyClass(ClassLoader var1, Class[] var2) throws IllegalArgumentException {
try {
return (Class) super.h.invoke(this, m7, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final Class getClass() throws {
try {
return (Class)super.h.invoke(this, m11, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Object newProxyInstance(ClassLoader var1, Class[] var2, InvocationHandler var3)
throws IllegalArgumentException {
try {
return (Object) super.h.invoke(this, m5, new Object[]{var1, var2, var3});
} catch (RuntimeException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final boolean isProxyClass(Class var1) throws {
try {
return (Boolean)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void wait(long var1, int var3) throws InterruptedException {
try {
super.h.invoke(this, m9, new Object[]{var1, var3});
} catch (RuntimeException | InterruptedException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m6 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getInvocationHandler",
Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m7 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getProxyClass",
Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"));
m11 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getClass");
m13 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notifyAll");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m8 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait");
m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("sayHello");
m12 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notify");
m5 = Class.forName("com.sun.proxy.$Proxy0").getMethod("newProxyInstance",
Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"),
Class.forName("java.lang.reflect.InvocationHandler"));
m10 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", Long.TYPE);
m4 = Class.forName("com.sun.proxy.$Proxy0").getMethod("isProxyClass", Class.forName("java.lang.Class"));
m9 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", Long.TYPE, Integer.TYPE);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
动态代理类继承了Proxy类,实现了Proxy0接口,首先观察静态初始化代码块,主要方法均是来自Object,Proxy,ClassLoader等类的方法,其中m3方法获取到了要代理的目标接口,sayHello方法具体转发到了自定义的InvacationHandler方法中,来执行自定义的逻辑。
3.Proxy类分析
首先看一下newProxyInstance方法:
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
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);
}
}
检查InvocationHandler非空,复制目标接口,进行安全检查,产生代理类,根据InvocationHandler,使用代理类的构造器来产生代理对象,返回代理对象。
其中重要的方法getProxyClass0方法:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
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);
}
可知动态代理类,对多代理65535个接口,代理类从缓存中取出。
其中KeyFactory
具体代理类的产生由ProxyClassFactory产生:
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
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.
*/
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());
}
}
}
代理类的名字前缀为$Proxy,并且有一个原子类型的数字(多线程安全)来标识代理类的序号。
proxyPkg定义了代理类的生成位置,与接口同一路径下,如果没有接口,则使用路径ReflectUtil.PROXY_PACKAGE 即com.sun.proxy
代理类的名字 String proxyName = proxyPkg + proxyClassNamePrefix + num; 包名+$Proxy+num;
调用ProxyGenerator.generateProxyClass来生成字节码文件
其中generateClassFile方法来产生字节码文件,具体涉及到class文件的结构,留着慢慢研究。
4.实现简单动态代理
使用JavaCompliler需要使用tools.jar,启动java的目录默认是%JAVA_HOME%/jre/bin/java.exe,这个目录的lib目录为%JAVA_HOME%/jre/lib,里面没有tools.jar,从%JAVA_HOME%/lib下面拷贝tools.jar到jre的lib目录下.
4.1定义InvocationHandler
4.2 定义InvocationHandler实现类,实现代码增强逻辑
4.3 定义类加载器
4.4 定义代理产生类
public class SimpleProxy {
private static String ln = "\r\n";
public static Object newProxyInstance(SimpleClassLoader loader,
Class<?> interfaces,
SimpleInvocationHandler h)
throws IllegalArgumentException{
/**
* 1.生成代理类的源代码
* 2.将生成的源代码输出到磁盘,保存为.java文件
* 3.编译源代码,并生成.java文件
* 4.将class文件中的内容,动态加载到JVM中
* 5.返回被代理后的代理对象
*/
try {
// 1.生成代理类的源代码
String src = generateProxyClassResource(interfaces);
// 2.将生成的源代码输出到磁盘,保存为.java文件
String path = SimpleProxy.class.getResource("").getPath();
System.out.println(path);
File file = new File(path+"$Proxy0.java");
FileWriter fw = new FileWriter(file);
fw.write(src);
fw.close();
// 3.编译源代码,并生成.class文件
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager manager = javaCompiler.getStandardFileManager(diagnostics, null, null);
Iterable iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
// 4.将class文件中的内容,动态加载到JVM中
Class proxyClass = loader.findClass("$Proxy0");
// 5.返回被代理后的代理对象
Constructor c = proxyClass.getConstructor(SimpleInvocationHandlerImpl.class);
return c.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generateProxyClassResource(Class<?> interfaces){
StringBuilder src = new StringBuilder();
src.append("package proxytest;").append(ln)
.append("import java.lang.reflect.Method;").append(ln)
.append("public class $Proxy0 implements ").append(interfaces.getName()).append("{").append(ln)
.append("private SimpleInvocationHandler h;").append(ln)
.append("public $Proxy0(SimpleInvocationHandler h){").append(ln)
.append("this.h=h;").append(ln)
.append("}").append(ln);
for(Method method:interfaces.getMethods()){
src.append("public ").append(method.getReturnType()).append(" ").append(method.getName()).append("() {").append(ln)
.append("try {").append(ln)
.append("Method m = ").append(interfaces.getName()).append(".class.getMethod(\"").append(method.getName()).append("\");").append(ln)
.append("this.h.invoke(this, m, new Object[]{});").append(ln)
.append("}catch (Throwable e){").append(ln)
.append("e.printStackTrace();").append(ln)
.append("}").append(ln)
.append("}").append(ln);
}
src.append("}");
return src.toString();
}
}
4.5调用实现代理功能
参考文献:
https://www.jianshu.com/p/3616c70cb37b
https://blog.csdn.net/zhangdefeng2008/article/details/79399898