手写实现动态代理

一般来说最常见的动态代理是这么写的:

1,正常版本

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

public class JDKProxy implements InvocationHandler {

private Object target;

public Object getInstance(Object  target){
    this.target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("JDProxy execute before...");
    Object result = method.invoke(target,args);
    System.out.println("JDProxy execute after...");
    return result;
}

}
2,改进版本

public class ProxyFactory {
public static Object getProxyInstance(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* System.out.println(proxy);
System.out.println(method);
System.out.println(args);*/
System.out.println(“日志记录begin”);
Object result = method.invoke(target, args);
System.out.println(“日志记录end”);
return result;
}
});
}
}
首先跟一下Proxy.newProxyInstance

System.out.println(sonProxy.getClass());

class com.sun.proxy. P r o x y 0 代 理 类 的 c l a s s 为 Proxy0 代理类的class为 Proxy0classProxy,就是意味着 Proxy.newProxyInstance的功能就是产生一个 P r o x y , 而 Proxy,而 Proxy,Proxy是什么呢?有一个骚操作

通过反编译工具查看class的源码

byte[] P r o x y 0 s = P r o x y G e n e r a t o r . g e n e r a t e P r o x y C l a s s ( " Proxy0s = ProxyGenerator.generateProxyClass(" Proxy0s=ProxyGenerator.generateProxyClass("Proxy0", new Class[]{Person.class});
FileOutputStream fileOutputStream = new FileOutputStream("E:// P r o x y 123. c l a s s " ) ; f i l e O u t p u t S t r e a m . w r i t e ( Proxy123.class"); fileOutputStream.write( Proxy123.class");fileOutputStream.write(Proxy0s);
fileOutputStream.flush();
fileOutputStream.close();
然后把 $Proxy123.class放到idea里面就能看到内容:

public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m3;
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 findLove() throws  {
    try {
        super.h.invoke(this, m3, (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.huffman.pattern.proxy.dynamic_jdk.Person").getMethod("findLove");
        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());
    }
}

}
可以看出来  Proxy.newProxyInstance具体做的就是生成一个代理类$Proxy,代理类里面克隆了当前类所有方法,而且调用findxxx()方法时其实是调用在定义InvocationHandler.invoke()定义的方法;

所以我们的手写动态代理的思路为:

1,直接生成$proxy.java

2,把 p r o x y . j a v a 编 译 成 proxy.java编译成 proxy.javaproxy.class

3,用类加载器把$proxy.class生成class实例

4,把class实例返回代理对象

所以重写Proxy的newProxyInstance用代码实现为:

public static Object newProxyInstance(MyClassLoader classLoader,Class<?>[] interfaces,MyInvocationHandler myInvocationHandler) throws IllegalArgumentException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.动态生成java文件源码
String src=generateSrc(interfaces);
//2.将java源码生成本地文件
String classPath = MyProxy.class.getResource("").getPath();
File file = new File(classPath + “ P r o x y 0. j a v a &quot; ) ; F i l e W r i t e r f i l e W r i t e r = n e w F i l e W r i t e r ( f i l e ) ; f i l e W r i t e r . w r i t e ( s r c ) ; f i l e W r i t e r . f l u s h ( ) ; f i l e W r i t e r . c l o s e ( ) ; / / 3. 动 态 编 译 j a v a 源 码 , 生 成 c l a s s 文 件 J a v a C o m p i l e r c o m p i l e r = T o o l P r o v i d e r . g e t S y s t e m J a v a C o m p i l e r ( ) ; S t a n d a r d J a v a F i l e M a n a g e r m a n a g e = c o m p i l e r . g e t S t a n d a r d F i l e M a n a g e r ( n u l l , n u l l , n u l l ) ; I t e r a b l e i t e r a b l e = m a n a g e . g e t J a v a F i l e O b j e c t s ( f i l e ) ; J a v a C o m p i l e r . C o m p i l a t i o n T a s k t a s k = c o m p i l e r . g e t T a s k ( n u l l , m a n a g e , n u l l , n u l l , n u l l , i t e r a b l e ) ; t a s k . c a l l ( ) ; m a n a g e . c l o s e ( ) ; / / 4. 加 载 c l a s s 文 件 生 成 C l a s s 实 例 C l a s s p r o x y C l a s s = c l a s s L o a d e r . f i n d C l a s s ( &quot; Proxy0.java&quot;); FileWriter fileWriter = new FileWriter(file); fileWriter.write(src); fileWriter.flush(); fileWriter.close(); //3.动态编译java源码,生成class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null); Iterable iterable = manage.getJavaFileObjects(file); JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable); task.call(); manage.close(); //4.加载class文件生成Class实例 Class proxyClass = classLoader.findClass(&quot; Proxy0.java");FileWriterfileWriter=newFileWriter(file);fileWriter.write(src);fileWriter.flush();fileWriter.close();//3.javaclassJavaCompilercompiler=ToolProvider.getSystemJavaCompiler();StandardJavaFileManagermanage=compiler.getStandardFileManager(null,null,null);Iterableiterable=manage.getJavaFileObjects(file);JavaCompiler.CompilationTasktask=compiler.getTask(null,manage,null,null,null,iterable);task.call();manage.close();//4.classClassClassproxyClass=classLoader.findClass("Proxy0”);
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);

    //        file.delete();

    //5.根据类型Class生成代理对象

    return c.newInstance(myInvocationHandler);
}

自定义类加载器就是把本地生成的$Proxy0.class加载到jvm

public class MyClassLoader extends ClassLoader {
private File classPathFile;

public MyClassLoader(){
    String classPath = MyClassLoader.class.getResource("").getPath();
    this.classPathFile = new File(classPath);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {

    String className = MyClassLoader.class.getPackage().getName() + "." + name;

    if(classPathFile != null){
        File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
        if(classFile.exists()){
            FileInputStream in = null;
            ByteArrayOutputStream out = null;

            try{
                in = new FileInputStream(classFile);
                out = new ByteArrayOutputStream();
                byte [] buff = new byte[1024];
                int len;
                while ((len = in.read(buff)) != -1){
                    out.write(buff,0,len);
                }
                return  defineClass(className,out.toByteArray(),0,out.size());
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(null != in){
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                if(out != null){
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
    return null;
}

}
至此,手动实现动态代理就完成了;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值