JDK的动态代理

一. 样例代码

1. Animal接口

public interface Animal {

    public void eat();

    public void run();
}

2. Cat

Cat 实现了 Animal 接口;

public class Cat implements Animal {

    @Override
    public void eat() {
        System.out.println("cat eat---");
    }

    @Override
    public void run() {
        System.out.println("cat run---");
    }

    /**
     * 此处的 hunt() 是 Cat 类自己的方法
     * 代理类 Proxy 实现的是 Animal 接口,Proxy 没有 hunt() 方法
     */
    public void hunt() {
        System.out.println("cat hunt---");
    }

}

3. MyInvocationHandler

MyInvocationHandler 需要实现 InvocationHandler 接口;

public class MyInvocationHandler implements InvocationHandler {

    private Animal animal;

    /**
     * 构造 MyInvocationHandler 对象的时候
     * 需要将被代理对象传进来作为私有属性
     * @param animal 被代理对象
     */
    public MyInvocationHandler(Animal animal) {
        this.animal = animal;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
        System.out.println("----代理对象前置工作执行");
        Object result = method.invoke(animal, args);
        System.out.println("----代理对象后置工作执行");
        return result;
    }
}

4. Test01

public class Test01 {

    public static void main(String[] args) {
        // 这一句是生成代理类的class文件,会在当前项目路径 com.sun.proxy 包下生成代理类
        // System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        // 1. 需要被代理的对象为 cat 对象
        Cat cat = new Cat();

        // 2. 创建出 InvocationHandler 对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(cat);

        // 3. 创建出代理对象,代理对象 proxy 是 Animal 接口的实现类
        Animal proxy = (Animal)Proxy.newProxyInstance(cat.getClass().getClassLoader(),
                cat.getClass().getInterfaces(),
                myInvocationHandler);

        // 4. 执行 proxy 的各种方法
        proxy.eat();
        proxy.run();
    }
}

执行结果如下:

----代理对象前置工作执行
cat eat---
----代理对象后置工作执行
----代理对象前置工作执行
cat run---
----代理对象后置工作执行

二. 代理类

1. 生成的代理类

1、jdk 的动态代理只有被代理对象实现了接口的情况下才能工作,因为代理对象 $Proxy0 需要继承 Proxy 类,并且代理对象会实现接口;如果被代理对象没有实现接口,不能使用 jdk 动态代理;

2、代理类 $proxy0 聚合了 InvocationHandler 对象;

3、代理类 $proxy0 的方法实际上执行的都是 invocationHandler.invoke();

package com.sun.proxy;

import com.zengqiang.dynamicjdk.Animal;
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 Animal {
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        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);
        }
    }

    public final void run() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void eat() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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("com.zengqiang.dynamicjdk.Animal").getMethod("run");
            m4 = Class.forName("com.zengqiang.dynamicjdk.Animal").getMethod("eat");
            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());
        }
    }
}

2. InvocationHandler

InvocationHandler 接口只有一个抽象方法,如下:

public interface InvocationHandler {

    /**
     * proxy: 代理类对象
     * method: 方法
     * args: 方法执行参数
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

3. Proxy

在生成代理类对象时,我们会调用 Proxy.newProxyInstance(),我们简单看下该方法;

1、生成代理类的 Class 对象;

2、根据 Class 对象和构造方法构造出代理对象;

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
    Objects.requireNonNull(h);
    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    // 1. 生成代理类的 Class 对象
    Class<?> cl = getProxyClass0(loader, intfs);

    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        // constructorParams = InvocationHandler.class
        // 获取代理类的构造方法,选择参数为InvocationHandler类型的构造方法
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        
        // 2. 根据构造方法和参数 invocationHandler 构造出代理类对象
        return cons.newInstance(new Object[]{h});
    } catch (Exception e) {
        throw e;
    }
}

Class<?> cl = getProxyClass0(loader, intfs) 中,生成并加载 Class 对象和 Proxy 的静态内部类 ProxyClassFactory 有关,我们简单看下 ProxyClassFactory 做了啥,了解即可;

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
    
    // 代理类型名称前缀
    private static final String proxyClassNamePrefix = "$Proxy";

    // 生成唯一数字使用
    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) {
            Class<?> interfaceClass = null;
            try {
                interfaceClass = Class.forName(intf.getName(), false, loader);
            } catch (ClassNotFoundException e) {
                throw ex;
            }
            
            //保证 interfaces 接口集合内全部都是接口
            if (!interfaceClass.isInterface()) {
                throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
            }
            
            //保证 interfaces 接口集合内没有重复接口
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
            }
        }

        // 生成的代理类的包名
        String proxyPkg = null;     
        // 生成的代理类 访问修饰符:public final ....
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

       	
        // 检查接口集合内的接口,看看有没有某个接口它的访问修饰符不是 public 的
        // 如果有哪个接口修饰符不是 public 的,那么我们生成代理类 class 就必须和它在一个包下
        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) {
            //如果接口没有非 public 的,那么使用默认的包名
            //可以看到默认是在 com.sun.proxy 包下
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }

        //获取唯一编号
        long num = nextUniqueNumber.getAndIncrement();
        //代理类名称 = 包名 + $proxy + 数字
        String proxyName = proxyPkg + proxyClassNamePrefix + num;

        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

        try {
            // 使用加载器加载这个二进制字节码文件到 jvm,并且返回此代理类 Class
            return defineClass0(loader, proxyName,
                    proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值