手写一个JDK动态代理的简单实现

前言

在【设计模式】——代理模式(静态)以及【设计模式】——代理模式(动态)中,我们已经基本了解了什么是代理模式,以及什么是静态代理,什么是动态代理。JDK动态代理以及Cglib动态代理其实底层实现原理都是字节码的重组,不过各自对应的代理场景不同,本文我们重点研究jdk动态代理。

通过前文的了解,我们已经知道在JDK动态代理中是JDK动态的帮我们生成一个名为$Proxy0的代理类,那么,我们本文来纯手写实现JDK动态代理,也就是我们自己生成这个代理类,与JDK动态代理的思想一致,只为简化,细节部分本文并未过多研究。

实现

在前文动态代理实现jdk动态代理中我们有这样一个类的调用关系图

其中需要引用到jdk的Proxy和InvocationHandler这两个类,这里我们自己简单实现MyProxy.java和MyInvocationHandler.java,由于需要动态生成代理类,那么就需要生成,编译,加载到jvm,因此我们实现了一个简单的类加载器MyClassLoader.java,此时类调用关系图略微变化

不多说,上代码,大多地方都有比较详细的注释

MyInvocationHandler.java

/** 用于自定义代理逻辑处理
 * @author WangZhiJun
 */
public interface MyInvocationHandler {
	/** invoke
	 * @param proxy 指被代理的对象
	 * @param method 要调用的方法
	 * @param args 方法调用时所需要的参数
	 * @return Object
	 * @throws Throwable 异常
	 */
	Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

MyProxy.java

这个类就是JDK动态代理的关键,其中进行了代理类的动态生成:

  1. 生成源代码
  2. 将生成的源代码输出到磁盘,保存为.java文件
  3. 编译源代码,并且生成.class文件
  4. 将class文件中的内容,动态加载到JVM中来
  5. 返回被代理后的代理对象
/** 生成代理对象的代码
 * @author WangZhiJun
 */
class MyProxy {
 
	private static final String ln = "\r\n";
 
    /** 通过此类为一个或多个接口动态的生成实现类
     * @param classLoader 类加载器
     * @param interfaces 得到全部的接口
     * @param h 得到InvocationHandler接口的子类实例
     * @return Object
     */
	static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h){
		try{
			//1、生成源代码
			String proxySrc = generateSrc(interfaces[0]);
			//2、将生成的源代码输出到磁盘,保存为.java文件
			String filePath = MyProxy.class.getResource("").getPath();
			File f = new File(filePath + "$Proxy0.java");
			FileWriter fw = new FileWriter(f);
			fw.write(proxySrc);
			fw.flush();
			fw.close();
			//3、编译源代码,并且生成.class文件
			JavaCompiler  compiler = ToolProvider.getSystemJavaCompiler();
			StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
			Iterable iterable = manager.getJavaFileObjects(f);
			CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
			task.call();
			manager.close();
			//4.将class文件中的内容,动态加载到JVM中来
			//5.返回被代理后的代理对象
			Class proxyClass = classLoader.findClass("$Proxy0");
			Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
			//这里先不删除生成的$Proxy0.java文件,实际上要删除的
			f.delete();
			return c.newInstance(h);
 
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
 
    /** 生成代理对象$Proxy0的源代码
     * @param interfaces 抽象对象
     * @return String
     */
	private static String generateSrc(Class<?> interfaces){
		StringBuilder src = new StringBuilder();
        src.append("package com.wang.proxy.custom.jdk.proxy;" + ln);
        //引入反射相关的包
        src.append("import java.lang.reflect.Method;" + ln);
        //动态代理类实现被代理接口,在此为Person类
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
        src.append("MyInvocationHandler h;" + ln);
        src.append("public $Proxy0(MyInvocationHandler 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{" + ln);
            src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});" + ln);
            src.append("this.h.invoke(this,m,null);" + ln);
            src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
            src.append("}" + ln);
        }
        src.append("}");
		return src.toString();
	}
}

MyClassLoader.java

/**将class重新动态load到JVM
 * @author WangZhiJun
 */
public class MyClassLoader extends ClassLoader{
 
	private File baseDir;
	
	MyClassLoader(){
		String basePath = MyClassLoader.class.getResource("").getPath();
		this.baseDir = new File(basePath);
	}
	
	@Override
	protected Class<?> findClass(String name) {
		String className = MyClassLoader.class.getPackage().getName() + "." + name;
		if(baseDir != null){
			File classFile = new File(baseDir,name.replaceAll("\\.", "/") + ".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();
						}
					}
					//先不删除,可以看到class文件内容
					//classFile.delete();
				}
			}
		}
		return null;
	}
}

开始测试

SomeService.java

//主业务接口
public interface SomeService {
    String first();
    String second();
}

SomeServiceImpl.java

//目标类
public class SomeServiceImpl implements SomeService{
    public String first() {
        // TODO Auto-generated method stub
        return "I Love You";
    }
    public String second() {
        // TODO Auto-generated method stub
        return "China";
    }
}

SomeServiceProxy.java

public class SomeServiceProxy implements MyInvocationHandler {
    private SomeService someService;
    public void setSomeService(SomeService someService) {
        this.someService = someService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(args);
    }
    public SomeService creatProxy() {
        SomeService proxy = (SomeService) MyProxy.newProxyInstance(new MyClassLoader(), someService.getClass().getInterfaces(), this);
        return proxy;
    }
}

Main方法

public static void main(String[] args) {
        //创建目标类
        SomeService someService = new SomeServiceImpl();
        //创建代理类
        SomeServiceProxy someServiceProxy = new SomeServiceProxy();
        //传入目标类
        someServiceProxy.setSomeService(someService);
        //创建代理类
        SomeService proxy = someServiceProxy.creatProxy();
        //执行代理类方法
        proxy.first();
    }

或者在SomeService和SomeServiceImpl的基础上直接这样写实现动态代理

 public static void main(String[] args) {
        //创建目标类
        SomeService someService = new SomeServiceImpl();
        SomeService proxy = (SomeService) MyProxy.newProxyInstance(new MyClassLoader(), someService.getClass().getInterfaces(), new MyInvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
        proxy.first();
    }

我们看看这个动态生成的$Proxy0代理类是怎么写的

public class $Proxy0 implements SomeService{
    MyInvocationHandler h;
    public $Proxy0(MyInvocationHandler var1) {
        this.h = var1;
    }
    public void findLove() {
        try {
            Method var1 = SomeService.class.getMethod("first");
            this.h.invoke(this, var1, (Object[])null);
        } catch (Throwable var2) {
            var2.printStackTrace();
        }
    }
}

这就是生成的动态代理类

此时我们就简单的实现了JDK的动态代理,不过JDK中实际的实现会更加复杂,更加细节!

文章转自:https://blog.csdn.net/qq_37141773/article/details/100015741

posted @ 2022-08-29 13:00  你樊不樊  阅读(71)  评论(0编辑  收藏  举报