所有分类
  • 所有分类
  • 未分类

Java代理模式写法1:JDK

简介

说明

本文用示例介绍Java代理模式(动态代理)的JDK写法

优缺点

优点

  1. 可以看到生成的代理类,有利于理解JDK代理模式的原理。

缺点

  1. 只能代理实现了接口的类。
  2. 写起来比较麻烦。

JDK动态代理的原理简述

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

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

实例

动态代理具体步骤

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

实例1:统计执行时间

需求:统计某个类所有方法的执行时间。

源码地址

此隐藏内容仅限VIP查看升级VIP

原始的任务

接口

package com.knife.designPattern.origin;

/**
 * 任务接口
 */
public interface Task {
    void dealTask(String taskName);

    void sayHello(String name);
}

实现类

package com.knife.designPattern.origin.impl;

import com.knife.designPattern.origin.Task;

public class TaskImpl implements Task {
    @Override
    public void dealTask(String taskName) {
        System.out.println("开始运行任务: " + taskName);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

代理类

代理类

package com.knife.designPattern.proxy;

import com.knife.designPattern.origin.Task;

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

public class TaskProxy implements InvocationHandler {
    private Object delegate = null;

    public TaskProxy(Task 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();
        Object result = method.invoke(delegate, args);
        long endTime = System.currentTimeMillis();
        System.out.println("运行时间: " + (endTime - startTime) + " ms");

        return result;
    }
}

代理工厂

package com.knife.designPattern.proxy;

import com.knife.designPattern.origin.Task;
import com.knife.designPattern.origin.impl.TaskImpl;

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

public class DynamicProxyFactory {
    public static Task getInstance() {
        Task origin = new TaskImpl();
        InvocationHandler handler = new TaskProxy(origin);
        return (Task) Proxy.newProxyInstance(
                origin.getClass().getClassLoader(),
                origin.getClass().getInterfaces(),
                handler);
    }
}

测试

package com.knife.designPattern;

import com.knife.designPattern.origin.Task;
import com.knife.designPattern.proxy.DynamicProxyFactory;

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

        Task proxy = DynamicProxyFactory.getInstance();
        System.out.println("代理类:" + proxy.getClass());
        System.out.println("-----------------------------------");
        proxy.dealTask("测试任务");
    }
}

运行结果

代理类:class com.sun.proxy.$Proxy0
-----------------------------------
开始运行任务: 测试任务
运行时间: 510 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<String> list = new ArrayList<>();
        List<String> listProxy=(List<String>) 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;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams = { InvocationHandler.class };

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }
    
    // 其他代码
}

生成的代理类的源码

查看自动生成的proxy class

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

  1. 设置参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
  2. 程序里调用:System.setProperty(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
  3. 在程序中直接调用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)。

2

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录