java动态代理机制之自定义实现动态代理


  

  Spring的开发方式之一就是面向切面编程即AOP,AOP的核心构造是切面,它将那些影响多个类的行为封装到可重用的模块中。而AOP的原理就是java的动态代理机制。

  本篇主要通过自定义一个Proxy类,来更深刻的理解动态代理的机制和原理。

  每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

public interface SelfInvocationHandler {
    /**
     *
     * @param proxy 指代我们所代理的那个真实对象
     * @param method 指代的是我们所要调用真实对象的某个方法的Method对象
     * @param args  指代的是调用真实对象某个方法时接受的参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method,Object[] args) throws Throwable ;

}

  Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

import javax.tools.JavaCompiler;
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.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 自定义代理类
 */
public class SelfProxy {
    private static String ln = "
";
    /**
     *
     * @param interfaces
     * @return
     */
    private static String generateStr(Class<?> interfaces) {
        StringBuffer src = new StringBuffer();
        src.append("package com.BXD._08Reflect.self;" + ln);
        src.append("import java.lang.reflect.Method;" + ln);
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
        src.append("SelfInvocationHandler h;" + ln);

        src.append("public $Proxy0(SelfInvocationHandler 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{");
            src.append("Method m=" + interfaces.getName() + ".class.getMethod("" + m.getName() + "", new Class[]{});" + ln);
            src.append("this.h.invoke(this,m,null);" + ln);
            src.append("}" + ln);
            src.append("catch(Throwable throwable){" + ln);
            src.append("throwable.printStackTrace();" + ln);
            src.append("}");
            src.append("}" + ln);
        }

        src.append("}");
        return src.toString();
    }

    /**
     *  Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象
     * @param loader 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
     * @param interfaces  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
     * @param h  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    public static Object newProxyInstance(SelfClassLoad loader, Class<?>[] interfaces, SelfInvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //1.生成源代码
        String proxySrc = generateStr(interfaces[0]);
        //2.将生成的源代码输出到磁盘,保存为,java文件
        String filePath = SelfProxy.class.getResource("").getPath();
        File javaFile = new File(filePath + "$Proxy0.java");
        FileWriter fw = new FileWriter(javaFile);
        fw.write(proxySrc);
        fw.flush();
        fw.close();
        //3.编译源代码,并且生成.class文件
        JavaCompiler compiler= ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manager=compiler.getStandardFileManager(null,null,null);
    
        Iterable iterable=manager.getJavaFileObjects(javaFile);
        JavaCompiler.CompilationTask task=compiler.getTask(null,manager,null,null,null,iterable);
        task.call();
        manager.close();
        //4.将class文件中的内容,动态加载到JVM中来
        Class proxyClass = loader.findClass("$Proxy0");
        //5.返回被代理后的代理对象
        Constructor c=proxyClass.getConstructor(SelfInvocationHandler.class);
        javaFile.delete();
        return c.newInstance(h);
    }
}

  自定义ClassLoad类,用来将动态生成的.class文件加载到JVM中

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

/**
 * Created by Administrator on 2018/6/23.
 * ClassLoader对象,对动态生成的.class文件加载到JVM
 */
public class SelfClassLoad extends ClassLoader{
    private File baseDir;

    /**
     *
     */
    public SelfClassLoad() {
        String basePath=SelfClassLoad.class.getResource("").getPath();
        this.baseDir=new File(basePath);
    }

    @Override
    protected Class<?> findClass(String name)  {
        String className = SelfClassLoad.class.getPackage().getName() + "." + name;
        if (baseDir!=null){
            File classFile=new File(baseDir,name.replace("\.","/")+".class");
            if (classFile.exists()){
                FileInputStream in=null;
                ByteArrayOutputStream out=null;
                try {
                    in=new FileInputStream(classFile);
                    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 (null!=out){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    classFile.delete();
                }
            }
        }
        return null;
    }
}

  定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外

**
 * Created by Administrator on 2018/6/23.
 * 定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口
 */
public class Meipo implements SelfInvocationHandler {

    /**
     * 这个就是我们要代理的真实对象
     */
    private Person target;
    public Object getInstance(Person target) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        this.target=target;
        Class clazz=target.getClass();
        System.out.println("被代理对象的class是:"+clazz);
        return new SelfProxy().newProxyInstance(new SelfClassLoad(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("我是媒婆");
        System.out.println("开始相亲。。。。");
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(this.target,args);
        System.out.println("结束相亲.......");
        return null;
    }
}

  

public interface Person {
    //相亲
    void findLove();
}

  

public class XiaoXingXing  implements Person{
    @Override
    public void findLove() {
        System.out.println("相亲要求");
        System.out.println("高富帅");
        System.out.println("有房车");
    }
}

  

/**
 * 自定义动态代理
 */
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Person xingxign=(Person)new Meipo().getInstance(new XiaoXingXing());
        System.out.println(xingxign);
        xingxign.findLove();

    }
}
  

  

原文地址:https://www.cnblogs.com/gousheng107/p/9222961.html