JDK动态代理


动态代理:字节码重组,即在每一个方法调用前后加些代码

Inter:

package proxy.jdk;

/**
 *
 */
public interface Inter {
    void findPerson();
}

Boss:

package proxy.jdk;

/**
 * Boss 到inter上找Person
 *
 */
public class Boss implements Inter {
    @Override
    public void findPerson() {
        System.out.println("我要找java架构师");
    }
}

WebApp:

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

/**
 * 找Person的App
 */
public class WebApp implements InvocationHandler {
    private Object target;//被代理对象的引用作为一个成员变量保存下来了
    //获取被代理人的个人资料
    public Object getInstance(Object target){
        this.target = target;
        Class<?> clazz = target.getClass();
        System.out.println("被代理的对象:"+clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object o = method.invoke(this.target,args);
        after();
        return o;
    }

    private void after() {
        System.out.println("---------------");
    }

    private void before() {
        System.out.println("找Person,找我WebApp");
        System.out.println("---------------");
    }
}

 

Test:

package proxy.jdk;

import sun.misc.ProxyGenerator;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
    * 1.拿到被代理对象的引用,然后获取它的接口
    * 2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
    * 3.把被代理对象的引用也拿到了
    * 4.重新动态生成一个class字节码
    * 5.然后编译
 */
public class Test {
    public static void main(String[] args){
        try {
            Inter obj = (Inter) new WebApp().getInstance(new Boss());
            System.out.println(obj.getClass());
            obj.findPerson();

            //获取字节码内容
            // 使用Jad反编译 
       // idea安装插件 Java Bytecode Decompiler即可
//            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Inter.class});
//            FileOutputStream os = new FileOutputStream("./$Proxy0.class");
//            os.write(bytes);
//            os.close();

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

反编译后的代码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.vip.proxy.jdk.Inter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Inter {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void findPerson() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.vip.proxy.jdk.Inter").getMethod("findPerson");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
View Code

发现$Proxy0 继承了 Proxy 类,同时还实现了我们的 Inter接口,而且重写了findPerson()等方法。而且在静态块中用反射查找到了目标对象的所有方法,而且保存了所 有方法的引用,在重写的方法用反射调用目标对象的方法

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

手动实现一个?

MyInvocationHandler:

package proxy.myproxy;

import java.lang.reflect.Method;

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

}

MyClassLoader:

package proxy.myproxy;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 代码生成、编译、重新动态load到JVM
 */
public class MyClassLoader extends ClassLoader {
    private File baseDir;

    public MyClassLoader() {
        String path = MyClassLoader.class.getResource("").getPath();
        this.baseDir = new File(path);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyClassLoader.class.getPackage().getName() + "." + name;
        if (baseDir!=null){
            File classFile = new File(baseDir,name+".class");
            if (classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] bytes = new byte[1024];
                    int len;
                    while ((len=in.read(bytes))!=-1){
                        out.write(bytes,0,len);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    classFile.delete();
                    if (null!=in){
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (null!=out){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

MyProxy:

package proxy.myproxy;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
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.Method;

/**
 * 生成代理对象
 */
public class MyProxy {
    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler h) {

        try {
            String proxySrc = generateSrc(interfaces[0]);
            //将生成的源代码输出到磁盘,保存为.java文件
            String path = MyProxy.class.getResource("").getPath();
            File file = new File(path+"$Proxy0.java");
            FileWriter fw = new FileWriter(file);
            fw.write(proxySrc);
            fw.flush();
            fw.close();
            //编译源代码,并且生成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(file);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();
            //将class文件中的内容,动态加载到JVM中来
            Class<?> proxyClass = loader.findClass("$Proxy0");
            //返回被代理后的代理对象
            //1 获取构造
            Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
            file.delete();
            //2 返回实例
            return c.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String ln = "\r\n";
    //生成源代码
    //参考反编译代码
    private static String generateSrc(Class<?> interfaces){
        StringBuffer src = new StringBuffer();
        String name = MyClassLoader.class.getPackage().getName();
        src.append("package "+name+";"+ln);
        src.append("import java.lang.reflect.Method;"+ln);
        src.append("public class $Proxy0 implements "+interfaces.getName());
        src.append("{"+ln);
        src.append("MyInvocationHandler invocationHandler;"+ln);
        src.append("public $Proxy0(MyInvocationHandler invocationHandler) {"+ln);
        src.append("this.invocationHandler = invocationHandler;"+ln);
        src.append("}"+ln);
        for (Method m:interfaces.getMethods()){
            src.append("public "+m.getReturnType()+" "+m.getName()+"(){"+ln);
            src.append("try{" + ln);
            src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});" + ln);
            src.append("this.invocationHandler.invoke(this,m,null);" + ln);
            src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
            src.append("}" + ln);
        }
        src.append("}");

        return src.toString();
    }

}

MyWebApp:

package proxy.myproxy;

import proxy.jdk.Inter;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *
 */
public class MyWebApp implements MyInvocationHandler {
    private Inter target;//被代理对象的引用作为一个成员变量保存下来了

    //获取被代理人的个人资料
    public Object getInstance(Inter target)throws Exception{
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理的对象:"+clazz);
        return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("找Person,找我MyWebApp");
        System.out.println("---------------");
        method.invoke(this.target,args);
        System.out.println("---------------");
        return null;
    }
}

Test:

package proxy.myproxy;

import proxy.jdk.Boss;
import proxy.jdk.Inter;

/**
 *
 */
public class Test {
    public static void main(String[] args){
        try {
            Inter obj = (Inter) new MyWebApp().getInstance(new Boss());
            obj.findPerson();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#### JDK Proxy 采用字节重组,重新生的对象来替代原始的对象以达到动态代理 的目的。JDK Proxy 生成对象的步骤如下:

1. 拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。

2. JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接 口。
3. 动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体 现)。

4. 编译新生成的 Java 代码.class。
5. 再重新加载到 JVM 中运行。

posted @ 2019-02-11 13:12  fly_bk  阅读(141)  评论(0编辑  收藏  举报