美文网首页JavaJava 杂谈
第一章1.2 动态代理-自己实现一个

第一章1.2 动态代理-自己实现一个

作者: yust5273 | 来源:发表于2019-06-07 16:13 被阅读0次
    //代码生成、编译、重新动态loader到JVM中
    public class YustClassLoader  extends ClassLoader{
        private File baseDir;
        public YustClassLoader() {
            String baseDir = YustClassLoader.class.getResource("").getPath();
            this.baseDir = new File(baseDir)  ;
        }
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            String className = YustClassLoader.class.getPackage().getName();
            if(Objects.nonNull(baseDir)){
                File classFile = new File(baseDir, name.replaceAll("\\.", "/") + ".class");
                if (classFile.exists()){
                    try(FileInputStream in =new FileInputStream(classFile); ByteArrayOutputStream 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 (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }finally {
                        classFile.delete();
                    }
                }
            }
            return null;
        }
    }
    
    public interface YustInvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    
    public class YustMeipo implements YustInvocationHandler {
        private Person target;//被代理对象的引用作为一个成员变量进行保存下来了
        public Object getInstance(Person target)throws  Exception{
            this.target=target;
            Class clazz = target.getClass();
            System.out.println("被代理对象的class是:"+clazz);
            return YustProxy.newProxyInstance(new YustClassLoader(), clazz.getInterfaces(), this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("我是媒婆:你的性别是:"+this.target.getSex()+"得给你找个异性");
            System.out.println("-----------------------------");
            method.invoke(this.target, args);
            System.out.println("-----------------------------");
            return null;
        }
    }
    
    public class YustProxy {
        private static String ln = "\r\n";
        public static Object newProxyInstance(YustClassLoader classLoader,Class<?>[] interfaces,YustInvocationHandler h){
            try{
                //1、生成源代码
                String proxySrc = generateSrc(interfaces[0]);
                //2、将生成的源代码输出到磁盘,保存为.java文件
                String filePath = YustProxy.class.getResource("").getPath();
                File f = new File(filePath + "$Proxy0.java");
                FileWriter fw = new FileWriter(f);
                fw.write(proxySrc);
                fw.flush();
                fw.close();
                //3、编译源代码,并且生成.class文件
                JavaCompiler  compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
                Iterable iterable = manager.getJavaFileObjects(f);
                CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
                task.call();
                manager.close();
                //4.将class文件中的内容,动态加载到JVM中来
                Class proxyClass = classLoader.findClass("$Proxy0");
                Constructor c = proxyClass.getConstructor(YustInvocationHandler.class);
                f.delete();
                //5.返回被代理后的代理对象
                return c.newInstance(h);
    
            }catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private static String generateSrc(Class<?> interfaces){
            StringBuffer src = new StringBuffer();
            src.append("package com.yust5273.proxy.custom;" + ln);
            src.append("import java.lang.reflect.Method;" + ln);
            src.append("import com.yust5273.proxy.custom.YustInvocationHandler" + ln);
            src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
            src.append("YustInvocationHandler h;" + ln);
            src.append("public $Proxy0(YustInvocationHandler h) {" + ln);
            src.append("this.h = h;" + ln);
            src.append("}" + ln);
            for (Method m : interfaces.getMethods()) {
                src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
                src.append("try{" + ln);
                src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});" + ln);
                src.append("this.h.invoke(this,m,null);" + ln);
                src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
                src.append("}" + ln);
            }
            src.append("}");
            return src.toString();
        }
    }
    
    public class YustTestFindLove {
        public static void main(String[] args){
            try {
                Person obj =(Person) new YustMeipo().getInstance(new XiaoXingXing());
                System.out.println(obj.getClass());
                obj.findLove();
                //代理对象的实现原理
                //1.拿到被代理对象的引用,然后获取它的接口、
                //2.JDK代理 就会重新生成一个类同时实现我们给的代理对象的所实现的接口
                //3.把被代理对象的引用也拿到了
                //4.重新生成一个class字节码
                //5.然后编译
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:第一章1.2 动态代理-自己实现一个

        本文链接:https://www.haomeiwen.com/subject/euzmxctx.html