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 = "\r\n";
/**
*
* @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);
}
}

猜你喜欢

转载自www.cnblogs.com/gousheng107/p/9222961.html