jdk动态代理

导读:本篇文章讲解 jdk动态代理,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

举例:小明因为工作忙,没时间恋爱,父母比较着急,给小明介绍相亲对象,安排相亲…

代码示例:

public interface People {
    public void marry();
}

public class XiaoMing implements People
{
    @Override
    public void marry() {
        System.out.println("我是小明,我要结婚啦");
    }
}

public class Parent implements InvocationHandler {
    private People people;

    public Parent(People people){
        this.people = people;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        method.invoke(people , null);
        after();
        return null;
    }

    private void before(){
        System.out.println("小明父母介绍相亲对象");
    }

    private void after(){
        System.out.println("小明父母帮小明带孩子");
    }
}

public class Test {
    public static void main(String[] args) {
        People proxyObj = (People)Proxy.newProxyInstance
        (Test.class.getClassLoader(), new Class<?>[]{People.class}, new Parent(new XiaoMing()));
        proxyObj.marry();
    }
}

这样一个简单的动态代理示例代码就创建好了,看一下main函数结果如图所示:
在这里插入图片描述
那问题来了,Parent类中的invoke方法是在哪里调用的呢?

在这里插入图片描述
通过上图可以看到,代理对象是一个名称为 $ Proxy0的对象,在$Proxy0中有一个名称为h的属性,这个h属性就是Parent对象。由于这个代理对象是在内存中的,通过以下的代码,可以通过流的方式将其导出来。

public static void createProxyClassFile(){
        byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class");
            fileOutputStream.write($Proxy0s);
            fileOutputStream.close();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这样在工程的根路径就生成了一个class文件,在ide中打开,就是长这个熊样:

import com.study.dongsq.proxy.People;
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 People {
    private static Method m1;
    private static Method m2;
    private static Method m0;
    private static Method m3;

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

    public final void marry() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.study.dongsq.proxy.People").getMethod("marry");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

可以看到,代理对象调marry方法,会调到super.h的invoke方法,这个h属性就是Parent
在这里插入图片描述
我们也可以利用类似javassist的技术,自己写一个MyProxy,代替jdk的Proxy,给Xiaoming创建一个代理对象。

public class MyProxy {
    private static String rt = "\r\n";
    private static String path = "D:\\study\\spring\\spring-source\\src\\main\\java\\com\\study\\dongsq\\myProxy\\";
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, MyInvocationHandler h){
    	//通过拼凑字符串的方式生成一个$proxy0
        String javaStr = getJavaStr(interfaces);
        //创建一个文件$Proxy0.java,并把字符串用流的方式写到这个文件里面
        createFile(javaStr);
        //用编译器编译成class文件
        compiler();
        //把class文件加载到jvm内存,并在内存中执行,返回代理实例
        MyClassLoader myClassLoader = new MyClassLoader(path);

        try {
            Class<?> $Proxy0 = myClassLoader.findClass("$Proxy0");
            Constructor<?> constructor = $Proxy0.getConstructor(MyInvocationHandler.class);
            Object o = constructor.newInstance(h);
            return o;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getJavaStr(Class<?>[] interfaces){
        Method[] methods = interfaces[0].getMethods();
        String proxyClassStr = "package com.study.dongsq.myProxy;" + rt
                +"import java.lang.reflect.Method;"+rt
                +"public class $Proxy0 implements " + interfaces[0].getName()
                +"{"+rt+"MyInvocationHandler h;" +rt
                +"public $Proxy0(MyInvocationHandler h){" + rt
                +"this.h=h;" +rt+ "}"
                +getMethodString(methods, interfaces[0]) +rt+"}";
        return proxyClassStr;
    }

    private static String getMethodString(Method[] methods, Class intf){
        String proxyMe = "";
        for(Method method : methods){
            proxyMe+="public void " + method.getName()
                    +"() throws Throwable {" +rt+ "Method md= "
                    +intf.getName() +".class.getMethod(\""+method.getName()
                    +"\",new Class[]{});" +rt
                    +"this.h.invoke(this, md, null);" +rt+ "}" +rt;
        }
        return proxyMe;
    }

    private static void createFile(String javaStr){
        File file = new File(path +"\\$Proxy0.java");
        try {
            FileWriter fw = new FileWriter(file);
            fw.write(javaStr);
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void compiler(){
        try {
            JavaCompiler systemJavaCompile = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardJavaFileManager = systemJavaCompile.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects(new File(path +"\\$Proxy0.java"));
            JavaCompiler.CompilationTask task = systemJavaCompile.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects);
            task.call();
            standardJavaFileManager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}




public class MyClassLoader extends ClassLoader {

    private File classPathFile;
    public MyClassLoader(String path){
        this.classPathFile = new File(path);
    }

    @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();
                }
            }
        }
        return null;
    }
}


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

用自己生成的Proxy去生成一个代理,执行效果是一样的
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13822.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!