自己写jdk动态代理及说明

应用场景介绍,有一个People接口,接口方法eat。接口实现ZhangSan类的eat方法,打印出字符串"张三吃饭喜欢看手机!!"。利用代理的方法,在eat方法调用前,打出字符串"吃饭之前要洗手!!!"。在eat方法调用后,打出字符串"吃完饭以后要洗碗!!!"。

一、标准的jdk的动态代理

1、接口

/**
 *
 * @date 2019/10/22 19:30
 */
package com.proxy;

/**
 * <类描述>
 * @date 2019/10/22 19:30
 * @version V1.0
 */
public interface People {

    void eat() throws Throwable;

    void sleep() throws Throwable;

    void sport() throws Throwable;
}

2、接口实现类

/**
 *
 * @date 2019/10/22 19:31
 * @version V1.0
 */
package com.proxy;

/**
 * <类描述>
 * @date 2019/10/22 19:31
 * @version V1.0
 */
public class ZhangSan implements People {
    @Override
    public void eat() throws Throwable {
        System.out.println("张三吃饭喜欢看手机!!");
    }

    @Override
    public void sleep() throws Throwable {
        System.out.println();
    }

    @Override
    public void sport() throws Throwable {
        System.out.println();
    }
}

3、InvocationHandler接口实现类

/**
 * @date 2019/10/22 19:36
 * @version V1.0
 */
package com.proxy;

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

/**
 * <类描述>
 * 声明类
 * @date 2019/10/22 19:36
 * @version V1.0
 */
public class ProxyHandler implements InvocationHandler {
    People people = null;

    public ProxyHandler(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("吃完饭以后要洗碗!!!");
    }
}

4、JDK动态代理使用测试

/**
 * @date 2019/10/22 19:39
 * @version V1.0
 */
package com.proxy;

import sun.misc.ProxyGenerator;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;

/**
 * <类描述>
 * @date 2019/10/22 19:39
 * @version V1.0
 */
public class Test {
    public static void main(String[] args) throws Throwable {
        //Proxy.newProxyInstance内存中创建了一个类
        People people = (People) Proxy.newProxyInstance(People.class.getClassLoader(),
                new Class[]{People.class},new ProxyHandler(new ZhangSan()));
        System.out.println("JDK的动态代理");
        people.eat();

    }
}



=============
执行结果如下:
JDK的动态代理
吃饭之前要洗手!!!
张三吃饭喜欢看手机!!
吃完饭以后要洗碗!!!

二、自己写动态代理

1、参考InvocationHandler接口,写自己的MyInvocationHandler接口

/**
 * @date 2019/10/23 10:09
 */
package com.proxy;

import java.lang.reflect.Method;

/**
 * <类描述>
 * @date 2019/10/23 10:09
 * @version V1.0
 */
public interface MyInvocationHandler {

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

JDK提供的InvocationHandler接口信息如下图

 

2、实现MyInvocationHandler接口的MyProxyHandler

/**
 * @date 2019/10/23 10:11
 * @version V1.0
 */
package com.proxy;

import java.lang.reflect.Method;

/**
 * <类描述>
 * @date 2019/10/23 10:11
 * @version V1.0
 */
public class MyProxyHandler implements MyInvocationHandler {

    People people = null;

    public MyProxyHandler(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("吃完饭以后要洗碗!!!");
    }
}

3、生成代理的MyProxy

/**
 * @date 2019/10/23 10:05
 * @version V1.0
 */
package com.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <类描述>
 * @date 2019/10/23 10:05
 * @version V1.0
 */
public class MyProxy {

    static String rt = "\r\n";

    public static Object createProxyInstance(ClassLoader loader,Class intf,MyInvocationHandler handler){

        Method[] methods = intf.getMethods();

        //1、创建一个java文件,用流的方式
        String proxyClass = "package com.proxy;" + rt
                + "import java.lang.reflect.Method;" + rt
                + "public class $Proxy0 implements " + intf.getName() + "{" + rt
                + "MyProxyHandler h;" + rt
                + "public $Proxy0(MyProxyHandler h) {" + rt
                + "this.h = h;" + rt + "}"
                + getMethodString(methods,intf) + rt + "}";

        //2、把类生成文件
        String fileName = "D:/workspace_study/springstudy/src/main/java/com/proxy/$Proxy0.java";
        File f = new File(fileName);
        try {
            FileWriter fw = new FileWriter(f);
            fw.write(proxyClass);
            fw.flush();
            fw.close();

            //3、编译java文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
            Iterable units = fileMgr.getJavaFileObjects(fileName);
            JavaCompiler.CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units);
            t.call();
            fileMgr.close();


            //4、把class加载到内存
            MyClassLoader loader1 = new MyClassLoader("D:/workspace_study/springstudy/src/main/java/com/proxy/");
            Class proxy0Class = loader1.findClass("$Proxy0");
            Constructor m = proxy0Class.getConstructor(MyProxyHandler.class);
            Object o = m.newInstance(handler);
            return o;

            //1、
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

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

4、MyClassLoader

/**
 * @date 2019/10/23 11:21
 * @version V1.0
 */
package com.proxy;

import java.io.*;

/**
 * <类描述>
 * @date 2019/10/23 11:21
 * @version V1.0
 */
public class MyClassLoader extends ClassLoader {

    private File dir;

    MyClassLoader(String path){
        dir = new File(path);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if(dir != null){
            File clazzFile = new File(dir,name + ".class");
            if(clazzFile.exists()){
                FileInputStream input = null;
                try {
                    input = new FileInputStream(clazzFile);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len;
                    while((len = input.read(buffer)) != -1){
                        baos.write(buffer,0,len);
                    }
                    return  defineClass("com.proxy." + name,baos.toByteArray(),0,baos.size());

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if(input != null){
                        try {
                            input.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return super.findClass(name);
    }
}

5、生成的$Proxy0信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值