[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 :  我们按照一贯的做法,继续把功能也传经来。。

详见下一篇


原文地址:https://www.cnblogs.com/robbychan/p/3786555.html