动态代理

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)
}

具体实现

  1. 检查接口(加载器能否加载该接口、接口是否重复、非公有接口必须在同一包下)
  2. 生成全限制名称(包名+$Proxy(long型数字))
  3. 生成代理的二进制字节数组表示
  4. 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();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值