zoukankan      html  css  js  c++  java
  • [Java] 动态代理 03 --(解决接口也当参数传)

    5.如果现在我们实现不是一个特定的接口(意思就是不是实现Moveable接口,而是实现的其他接口),那我们怎么办喃?
      那我们把接口也当参数传进来
    package com.bjsxt.proxy;
    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;
    import java.net.URL;
    import java.net.URLClassLoader;
    
    import javax.tools.JavaCompiler;
    import javax.tools.JavaCompiler.CompilationTask;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    
    import com.bjsxt.proxy.Moveable;
    import com.bjsxt.proxy.Tank;
    
    public class Proxy {
        // 这个类的作用就是用来产生新的代理类
        public static Object newProxyInstance(Class infce) throws IOException,
                ClassNotFoundException, SecurityException, NoSuchMethodException,
                IllegalArgumentException, InstantiationException,
                IllegalAccessException, InvocationTargetException { // JDK6 Complier
                                                                    // API, CGLib,
                                                                    // ASM
            // API, CGLib,
            // ASM
            /*
             * 把这个类当成一个string的字符串(源码) 现在我们假设,我们能把这字符串编译,生成类,放在内存,来产生对象
             * 
             * 动态代理就是你看不到代理类,你只需要调用一个方法( Proxy的newProxyInstance()方法),
             * 会自动给你返回一个代理类对象,这个对象的产生是由内部动态的生成一段代码,编译完成的
             */
            String methodStr = "";
            String rt = "
    ";
    
            Method ms[] = com.bjsxt.proxy.Moveable.class.getMethods();
            for (Method m : ms) {
                methodStr = "@Override"  + rt + "    public void "
                        + m.getName() + "() {" + rt
                        + "        long start = System.currentTimeMillis();" + rt
                        + "        t." + m.getName() + "();" + rt
                        + "        long end = System.currentTimeMillis();" + rt
                        + "        System.out.println((end - start));" + rt + "    }";
            }
    
            String src = "package com.bjsxt.proxy;" + rt + rt +
    
            "public class TankTimeProxy implements " + infce.getName() + " {" + rt +
    
            "    public TankTimeProxy(Moveable t) {" + rt + "        super();" + rt
                    + "        this.t = t;" + rt + "    }" + rt + rt
                    + "    Moveable t;" + rt + rt
                    + methodStr
                    + rt + "}";
            // 获取当前系统目录(就是项目根目录)
            String fileName = "d:/src/com/bjsxt/proxy/TankTimeProxy.java";
            System.out.println(fileName);
    
            // System.out.println(fileName);
            File f = new File(fileName);
            FileWriter writer = new FileWriter(f);
            writer.write(src);
            writer.flush();
            writer.close();
            // 看是否生成代码,右键项目,刷新就OK了
            /*
             * 第三步 : 我们来生成一个类
             */
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 拿到java的编译器
    
            System.out.println(compiler.getClass().getName());
    
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,
                    null, null);// 文件的 管理器
    
            Iterable untis = fileMgr.getJavaFileObjects(fileName); // 找到文件,把文件放在
                                                                    // Iterable(数组)中
    
            CompilationTask t = compiler.getTask(null, fileMgr, null, null, null,
                    untis);// 定好编译文件任务
            t.call(); // 编译文件
    
            fileMgr.close();// 关闭文件管理器
            /*
             * 运行 :
             * 编译之后,打开Navigator(这个可以看到类详细的变化,就是看得到class文件的产生),就会看到多了一个TankTimeProxy
             * .class 文件,第三步成功
             */
            // Load into memory and create an instance
            /*
             * 第四步: 我们把文件加入内存(原本一般的做法是class.loader,就OK了,但是调用这个方法的前提就是,
             * 你的class文件目录必须在classpath的文件目录下),我们这里用一种通用的做法
             */
            // 这里使用url加载器
            URL[] urls = new URL[] { new URL("file:/" + "d:/src/") };
            URLClassLoader ul = new URLClassLoader(urls); // 这里需要一个数组地址
            Class c = ul.loadClass("com.bjsxt.proxy.TankTimeProxy");
            // 把类加到内存
            System.out.println(c);
            // 测试:输出c,OK,第四步完成
            // 最后一步,生成对象
            // 反射来创建对象
            Constructor ctr = c.getConstructor(Moveable.class); // 获取构造方法
    
            Object m = (Object) ctr.newInstance(new Tank());
            // m.move();
            return m;
        }
    
    }
    Client.java
    package com.bjsxt.proxy;
    import java.io.Serializable;
    
    public class Client {
        public static void main(String[] args) throws Exception {
            Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class);
            m.move();
        }
    }
    //可以对任意的对象、任意的接口方法,实现任意的代理
    Moveable
    package com.bjsxt.proxy;
    public interface Moveable {
    	void move();
    }

    这样就能保证,即使方法不统一,我也可以让每个方法都执行计时功能哦

    动态代理-你不必知道我存在

     @(1), 其实将 class 文件直接生成在 bin 目录下就可以了。但是这样,我们讲了一点新知识出来, 就是要告诉你,在哪一个目录下,都可以做到。
        其实 字符串 可以动态生成。
     @(2), 站在 java 虚拟机 的角度来看, 每一个类,class 是一个对象, 每一个类里面的构造方法也算一个对象。
     @(3), JDK 的动态代理生成 (有时候是二进制)

     6. 现在我们来解决下一个问题,我们每个接口都是来实现计时功能的?显然不是,那肯定还有其他功能三

             那我们怎么样来做,才可以是我们想实现什么功能,就实现什么功能喃?动态代理?

       answ :  我们按照一贯的做法,继续把功能也传经来。。

    详见下一篇


  • 相关阅读:
    python数字
    Python数据类型
    Python表达式与运算符
    正则表达式
    计划任务
    nfs服务
    nginx反向代理+负载均衡
    samba安装测试
    自定义centos7 yum仓库
    token过期时间
  • 原文地址:https://www.cnblogs.com/robbychan/p/3786555.html
Copyright © 2011-2022 走看看