jdk动态代理
优点:相比于静态代理只需编写一个InvocationHandler ,真正的代理类由jdk在运行时创建
缺点:只能代理实现了接口的委托类
InvocationHandler接口
代理实例关联的调用处理程序,当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
public interface InvocationHandler {
//代理类、代理方法、方法参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Proxy类
动态代理类
public class Proxy implements java.io.Serializable {
//代理类的调用处理程序
protected InvocationHandler h;
//传入调用处理程序的构造方法
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
//给出类加载器和接口数组的代理类的Class对象
@CallerSensitive
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
//返回指定接口的代理类的实例,与getProxyClass类似,都生成对应的代理类Class对象,最后调用newInstance(h)
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
}
具体实现
- 检查接口(加载器能否加载该接口、接口是否重复、非公有接口必须在同一包下)
- 生成全限制名称(包名+$Proxy(long型数字))
- 生成代理的二进制字节数组表示
- defineClass返回类对象
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
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");
}
//验证类对象是否为接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//验证接口是否重复
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;
//如果接口不是公有的,则这些接口必须在同一个包中
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) {
// 如果没有非公有接口则使用包名:com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 生成全限制名称 com.sun.proxy$Proxy(long)
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成代理类二进制字节数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//根据字节数组返回类型对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
查看ProxyGenerator.generateProxyClass方法生成的二进制字节数组
//将ProxyGenerator.generateProxyClass的二进制数组写入文件
//byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{Log.class});
//jdk自动生成的代理类
public final class $Proxy extends Proxy implements Log {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy(InvocationHandler var1) throws {
//Proxy中的构造方法
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
//抛出未检查异常(包括调用处理程序处未声明的已检查异常)
throw new UndeclaredThrowableException(var4);
}
}
//继承自Log中的方法
public final void log(int var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} 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 int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//类初始化时执行,加载类获得方法
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("proxy.Log").getMethod("log", Integer.TYPE);
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
简单手写实现动态代理
1.根据传入接口数组编写底层代理类的java源码
//生成的真实代理类继承MyProxy,实现对应接口
public static byte[] generate(Class<?>[] interfaces) {
String name = interfaces[0].getName();
//获得包名
String packageName = name.substring(0, name.lastIndexOf(".") + 1);
StringBuffer sb = new StringBuffer();
sb.append("package proxy;\n");
sb.append("import proxy.imp.MyProxy;\n");
sb.append("import java.lang.reflect.Method;\n");
sb.append("import proxy.imp.MyInvocation;\n");
sb.append("import java.lang.reflect.UndeclaredThrowableException;\n");
sb.append("\n");
sb.append("public final class $Proxy0 extends MyProxy implements ").append(name.substring(name.lastIndexOf(".") + 1)).append(" {\n");
//生成构造方法
sb.append("\tpublic $Proxy0(MyInvocation h){\n");
sb.append("\t\tsuper(h);\n");
sb.append("\t}\n");
//生成代理的方法
Method[] methods = interfaces[0].getMethods();
for (Method method : methods) {
String methodName = method.getName();
String returnType = method.getReturnType().getSimpleName();
sb.append("\t").append("@Override\n");
sb.append("\t").append("public final ").append(returnType).append(" ").append(methodName).append("(");
Parameter[] parameters1 = method.getParameters();
StringBuffer params = new StringBuffer();
int count = 0;
for (Parameter parameter : parameters1) {
sb.append(parameter.getType().getSimpleName()).append(" var").append(count++).append(",");
params.append(parameter.getType().getSimpleName()).append(".class,");
}
//删除方法参数中最后一个,
if (parameters1.length > 0) {
sb.deleteCharAt(sb.length() - 1);
params.deleteCharAt(params.length() - 1);
}
sb.append("){\n");
//加载接口方法
sb.append("\t\t").append("try{\n");
sb.append("\t\t\t").append("Method m =").append("Class.forName(\"").append(name).append("\").getMethod(\"").append(methodName);
sb.append("\"");
if (params.length() > 0) {
sb.append(",").append(params.toString());
}
sb.append(");\n");
sb.append("\t\t\t");
if (!"void".equals(returnType)) {
sb.append("return (").append(returnType).append(")");
}
sb.append("super.invocation.invoke(this,m,new Object[]{");
int count2=0;
while (count2 < count) {
sb.append("var").append(count2);
if (++count2 < count) {
sb.append(",");
}
}
sb.append("});\n");
sb.append("\t\t}catch (Throwable e){\n");
sb.append("\t\t\tthrow new UndeclaredThrowableException(e);\n");
sb.append("\t\t}\n");
sb.append("\t}\n\n");
}
sb.append("}");
System.out.println(sb.toString());
return sb.toString().getBytes();
}
2.生成.java文件后,调用编译器生成class文件
//从程序中调用Java编程语言编译器的接口
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
//文件管理器基于java.io.File
StandardJavaFileManager standardFileManager = javaCompiler.getStandardFileManager(null, null, null);
System.out.println("加载源码路径:" + file.getPath());
Iterable javaFileObjects = standardFileManager.getJavaFileObjects(file.getPath());
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
//编译
try {
task.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
standardFileManager.close();
} catch (IOException e) {
e.printStackTrace();
}
}
3.调用类加载器加载class文件,返回class对象,然后获得构造器,生成对应实例返回
//类加载器加载生成Class对象
Class<?> aClass = loader.findClass(file.getPath());
//调用构造器生成代理对象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(MyInvocation.class);
return declaredConstructor.newInstance(invocation);
cglib动态代理
- 如果传入多个Callbacks则需设置过滤器CallbackFilter,否则报错
- CallbackFilter通过accept(Method)int方法返回第一个满足条件的拦截器
优点:相比于jdk动态代理只能对接口进行代理 ,cglib动态代理通过继承方式使委托类无需继承接口也能被代理,创建的动态代理对象性能更高。
缺点:不能对final类及方法进行代理,创建动态代理对象的时间耗费更长
methodProxy根据索引(FastClassInfo中定义)来调用对应方法
invokeSuper调用的是代理类动态生成的findClass索引对应的方法,此时传入代理类对象会调用其super.XX()方法,执行父类的方法。
invoke调用的是真实类动态生成的findClass索引对应的方法,如果此时传入对象为代理类则会出现栈溢出。
MethodInterceptor接口
public interface MethodInterceptor extends Callback {
//var1代理类,var2原方法,var3方法参数,var4代理类中方法
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
//例:methodProxy.invokeSuper(var1,var3); 使用f2表示代理类
//method.invoke(真实类,参数); 使用f1表示真实类
}
基本调用方式,proxy调用方法时会首先检查是否存在methodInterceptor,如果存在则调用该接口中的intercept方法
Enhancer en = new Enhancer();
//设置被代理类
en.setSuperclass(Test.class);
//设置方法拦截回调
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return null;
}
});
//创建代理类
Object proxy = en.create();