web框架中用到的设计模式专题

手敲JDK动态代理实现

2019-06-20  本文已影响0人  先生zeng

上一篇文章其实已经把动态代理底层实现讲的很清楚的,这篇想要直接上代码的,毕竟实现的步骤其实是差不多的。
https://www.jianshu.com/p/72d1448a29f0
步骤如下:
1.新建一个XXXProxy类,然后获取一个代理类实例。
2.新建一个XXXInvocationHandle抽象接口,还有invoke方法。
3.新建一个类加载器,这样根据双亲委派机制,可以加载我们的代理类,每个类在JVM中都有各自的类加载器的,JVM本身有提供,我们也可以自己定义。
4.重新newInstance方法,里面的生成步骤如下:
// 1.动态生成源代码.java文件
// 2.把java文件输出到磁盘
// 3.把生成的.java文件编译成
//获取系统编译器
//4.编译生成的.class文件加载到jvm中来
/编译完成后删除
// 5.返回字节码重组以后新的代理对象。
最后测试。

直接撸代码了哈。

ZXYProxy类如下:

public class ZXYProxy{

    public static final String ln = "\r\n";

    public static Object newProxyInstance(ZXYClassLoader classLoader,Class<?> [] interfaces,ZXYInvocationHandle h){

            try {
//         1.动态生成源代码.java文件
                String src = generateSrc(interfaces);
//         2.把java文件输出到磁盘
                String path = ZXYProxy.class.getResource("").getPath();
                System.out.println(path);
                File f = new File(path + "$Proxy0.java");
                FileWriter fw = new FileWriter(f);
                fw.write(src);
                fw.flush();
                fw.close();
//          3.把生成的.java文件编译成
                //获取系统编译器
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
                Iterable javaFileObjects = standardFileManager.getJavaFileObjects(f);

                JavaCompiler.CompilationTask task = compiler.getTask(null,standardFileManager,null,null,null,javaFileObjects);
                task.call();
                standardFileManager.close();

                //4.编译生成的.class文件加载到jvm中来
                Class proxyClass = classLoader.findClass("$Proxy0");
                Constructor constructor = proxyClass.getConstructor(ZXYInvocationHandle.class);
                //编译完成后删除
                f.delete();

                //  5.返回字节码重组以后新的代理对象。
                return constructor.newInstance(h);

            }catch (Exception e){
                e.printStackTrace();
            }
        return null;
    }

    private static  String generateSrc(Class<?>[] interfaces){
        StringBuffer sb=new StringBuffer();
        sb.append("package com.zxy.test.gupao.tom.proxy.custom;" + ln);
        sb.append("import com.zxy.test.gupao.tom.proxy.staticed.Person;" + ln);
        sb.append("import java.lang.reflect.Method;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);

        sb.append("ZXYInvocationHandle h;" + ln);
        sb.append("public $Proxy0(ZXYInvocationHandle h) {" + ln);

           sb.append("this.h = h;" + ln);
        sb.append("}" + ln);

        for(Method m : interfaces[0].getMethods()){
            sb.append("public "+ m.getReturnType()+" "+ m.getName() +"() {"+ ln);
                sb.append("try {"+ln);
                    sb.append("Method m = "+interfaces[0].getName() +".class.getMethod(\""+m.getName()+"\",new Class[]{});"+ ln);
                    sb.append("this.h.invoke(this,m,null);"+ln);
                sb.append("}catch(Throwable e){"+ln);
                sb.append("e.printStackTrace();"+ln);
                sb.append("}" + ln);
            sb.append("}");
        }
        sb.append("}"+ln);

        return sb.toString();
    }
}

ZXYInvocationHandle:
``java
public interface ZXYInvocationHandle {

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

}

接下来是类加载器
ZXYClassLoader
```java
public class ZXYClassLoader extends ClassLoader{

    private File classPathFile;

    public ZXYClassLoader(){

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

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

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

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

                try{
                    in=new FileInputStream(file);
                    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;
    }
}

然后是媒婆代理类:

public class CustomerMeiPo implements ZXYInvocationHandle{

    private Person target;

    public Object getInstance(Person target)throws Exception{
        this.target=target;

        Class<? extends Person> aClass = target.getClass();

        return ZXYProxy.newProxyInstance(new ZXYClassLoader(),aClass.getInterfaces(),this);

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
        System.out.println("开始物色");

        method.invoke(this.target,args);

        System.out.println("如果合适的话,就准备办事");
        return null;
    }
}

还有一个代理类的接口,没什么哈。

public interface Person {

    public void findLove();

    public void zufangzi();

    public void buy();

    public void findJob();

    //......
}

这是被代理类。

public class XieMu implements Person {

    @Override
    public void findLove(){
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("胸大,6块腹肌");

    }

    @Override
    public void zufangzi() {
        System.out.println("租房子");
    }

    @Override
    public void buy() {
        System.out.println("买东西");
    }

    @Override
    public void findJob() {
        System.out.println("月薪20K-50k");
        System.out.println("找工作");
    }
}

最后,终于结束了。测试类:

public class ZXYProxyTest {

    public static void main(String[] args) {

        try {
            Person obj = (Person)new CustomerMeiPo().getInstance(new XieMu());
            System.out.println(obj.getClass());
            obj.findLove();
            //打印出来
            byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
            os.write(bytes);
            os.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果如下:

image.png

还差一点,去我们的E盘看看,已经编译好一个代理类了。跟JDK实现的是一样的。


ok,撸完收工!

然后如果没感觉我这篇文章都在贴代码,可以看我的上一篇文章。详细讲解了JDK是怎么实现了。步骤是一样一样的。

可能有的看到了,我是看视频学习的,嗯,不过每行代码还有源码分析都是自己去分析的。每行都是自己敲的,整理分享不易,希望大家多多支持。

感谢您阅读我的文章,如果满意可以帮我点赞,谢谢哈。
如果对文章部分还有什么见解或者疑惑,可以私信评论我,欢迎技术讨论。如果需要获取完整的文件资源,可以加我微信z985085305,获取我整理的全套笔记。
思想的碰撞最能促进技术的进步哦。

上一篇 下一篇

猜你喜欢

热点阅读