栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDK动态代理--实例/原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDK动态代理--实例/原理

原文网址:JDK动态代理--实例/原理_IT利刃出鞘的博客-CSDN博客

简介

说明

本文用示例介绍JDK动态代理的用法。

JDK动态代理的原理简述

生成的代理类继承Proxy,且实现了业务的接口,Proxy中有InvocationHandler的实现类的引用。

调用被代理的类的方法时,会调用父类(Proxy)的InvocationHandler成员的invoke方法。

限制

只能代理实现了接口的类。

实例

动态代理具体步骤:

    通过实现 InvocationHandler 接口创建自己的调用处理器;通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
实例1:统计执行时间
package com.example.a;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理接口
interface ExecutionTime {
    public void dealTask(String taskName);
    public void sayHello(String name);
}

//被代理类
class ExecutionTimeImpl implements ExecutionTime {
    //这里打印出任务名,并休眠500ms模拟任务执行了很长时间
    @Override
    public void dealTask(String taskName) {
        System.out.println("Task is running: "+taskName);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void sayHello(String name) {
        System.out.println("hello" + name);
    }
}

// 动态代理类对应的调用处理程序类
class ExecutionTimeProxy implements InvocationHandler {
    private Object delegate = null;

    public ExecutionTimeProxy(ExecutionTime delegate) {
        this.delegate = delegate;
    }

    // proxy:代理类代理的真实代理对象。例如:com.sun.proxy.$Proxy0
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        method.invoke(delegate, args);
        long endTime = System.currentTimeMillis();
        System.out.println("Elapsed time: "+(endTime - startTime)+" ms");

        return null;
    }
}

//生成动态代理对象的工厂
class DynamicProxyFactory {
    public static ExecutionTime getInstance(){
        ExecutionTime origin = new ExecutionTimeImpl();
        InvocationHandler handler = new ExecutionTimeProxy(origin);
        ExecutionTime proxy = (ExecutionTime) Proxy.newProxyInstance(
                origin.getClass().getClassLoader(),
                origin.getClass().getInterfaces(),
                handler);
        return proxy;
    }
}

public class Demo{
    public static void main(String[] args) {
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        ExecutionTime proxy = DynamicProxyFactory.getInstance();
        System.out.println(proxy.getClass());
        System.out.println("-----------------------------------");
        proxy.dealTask("TestTask");
    }
}

运行结果

class org.example.a.$Proxy0
-----------------------------------
Task is running: TestTask
Elapsed time: 500 ms
实例2:ArrayList
package org.example.a;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        final ArrayList list = new ArrayList<>();
        List listProxy=(List) Proxy.newProxyInstance(
                        list.getClass().getClassLoader(),
                        list.getClass().getInterfaces(),
                        new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                return method.invoke(list,args);
                            }
                        });
        listProxy.add("hello") ;
        listProxy.add("world") ;
        System.out.println(list);
    }
}

运行结果

[hello, world]
原理 相关类

InvocationHandler

package java.lang.reflect;

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

Proxy

package java.lang.reflect;

public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    
    private static final Class[] constructorParams = { InvocationHandler.class };

    
    private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    
    protected InvocationHandler h;

    
    private Proxy() {
    }
    
    // 其他代码
}
生成的代理类的源码

查看自动生成的proxy class

默认在运行时程序自动生成proxy class,若想看下自动生成的proxy class有三种方法

    设置参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true程序里调用:System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");在程序中直接调用ProxyGenerator.generateProxyClass()来生成动态代理类,如下所示:
String name = "$Proxy00";
byte[] data = ProxyGenerator.generateProxyClass("com.sun.proxy." + name, new Class[] { Hello.class } );
FileOutputStream out = new FileOutputStream("/tmp/" + name + ".class" );
out.write(data);
out.close();

以前边的“时间统计示例”为例,在main方法中最前边添加

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

执行结果:生成了$Proxy0.class

$Proxy0.class代码如下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.example.a;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements ExecutionTime {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("org.example.a.ExecutionTime").getMethod("sayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("org.example.a.ExecutionTime").getMethod("dealTask", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    
    public final void dealTask(String 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 void sayHello(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    
    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);
        }
    }

    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);
        }
    }
}
JDK动态代理只能代理接口

        类Proxy的作用是保存自定义的InvocationHandler,便于在方法代理时执行自定义InvocationHandler的逻辑。由于$Proxy0已经继承了类Proxy,所以不能再extends一个类了,所以只能implements一个接口了。

执行流程

创建代理类

Proxy.newProxyInstance时,入参:代理类的类加载器和接口、InvocationHandler接口的实现类。返回:proxy(Proxy$0类型)

执行流程

proxy.dealTask(Proxy$0的dealTask方法)
    // Proxy类的h(前边保存的InvocationHandler接口对象)的invoke方法
    // m1是通过反射获得的方法,var1是传进来的String类型的参数
    super.h.invoke(this, m1, new Object[]{var1})
        ExecutionTimeProxy(InvocationHandler接口对象)的invoke方法
            // Method类的invoke方法
            method.invoke(delegate, args);
生成Proxy.class的流程

Proxy.newProxyInstance=> ProxyClassFactory.apply=> ProxyGenerator.generateProxyClass=> .class文件=> Class对象=> Proxy实例

关于ProxyGenerator.generateProxyClass(),内部主要是按照固定”模板“按照字节码格式生成对应class字节码,大致是:实现要代理接口的所有public方法及固定的方法(hashCode、equals和toString),然后调用InvocationHandler的invoke方法。(就是走到示例代码中的HelloProxy类(class HelloProxy implements InvocationHandler)。

其他网址

JDK动态代理为什么不能代理类 - 知乎

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737081.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号