粗略实现jdk中的接口动态代理

本文通过自定义类加载器及动态编译技术,详细解析了JDK动态代理的实现过程,包括生成代理类源码、编译源码、创建代理对象,并通过一个具体的例子展示了动态代理的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习了下代理设计模式对jdk中的动态代理感到好奇是怎么实现的,于是查看了类加载器,动态编译以及jdk动态代理原理资料试着实现了一下

一 核心代码1:生成代理代理对象类 两个核心方法,newProxyInstance用于产生代理对象,generateJavaSourceByTemplate用于生成源代码字符串

public class MyProxy {
	private static String className;
	private static String initPackageName = "com.colin.proxy";
	/**
	 * 产生代理对象方法
	 * @param classLoader 传入被代理类的类加载器
	 * @param interfaces 传入代理类实现的接口
	 * @param invocationHandler 传入invocationHandler对象
	 * @return 返回生成的代理对象
	 */
	public static Object newProxyInstance(ClassLoader classLoader,Class[] interfaces,InvocationHandler invocationHandler) {
		//产生源码
		String source = generateJavaSourceByTemplate(null, interfaces);
		//将源码编译
		try {
			Class<?> c = DynamicCompilerRAM.compiler(source, className, initPackageName+"."+className,classLoader);
			//返回代理对象
			Constructor constructor = c.getConstructor(InvocationHandler.class);
			Object object = constructor.newInstance(invocationHandler);
			System.out.println("代理对象:"+object);
			return object;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("生成代理对象出错");
		}
		return null;
	}
	/**
	 * 产生源码字符串
	 * @param packageName 包名
	 * @param interfaces 接口数组
	 * @return 返回源码
	 */
	private static String generateJavaSourceByTemplate(String packageName,Class[] interfaces) {
		className = "$proxy"+interfaces.hashCode();//生成类名
		if(packageName!=null&&!"".equals(packageName)) {//如果不指定包的名字,默认使用
			initPackageName = packageName;
		}
		//组装java源码
		StringBuilder sb = new StringBuilder();
		sb.append("package "+initPackageName+";");
		sb.append("public class "+className+" implements ");
		sb.append(interfaces[0].getName());
		//拼接实现接口
		for(int i=1;i<interfaces.length;i++) {
			sb.append(","+interfaces[i].getName());
		}
		
		//建立构造函数 必须传入一个InvocationHandler
		sb.append("{");
		sb.append("private classaboutproxy.InvocationHandler invocationHandler;");
		sb.append("public "+className+"(classaboutproxy.InvocationHandler invocationHandler)"
				+ "{this.invocationHandler=invocationHandler;}");
		
		//实现接口里面的方法
				for (Class clazz : interfaces) {
					Method[] ms = clazz.getMethods();
					for (Method method : ms) {
						Class[] parameterTypes = method.getParameterTypes();
						//拼接参数类型class数组 为后面获取方法做准备
						StringBuilder psb = null;
						if(parameterTypes.length>0) {
							psb = new StringBuilder();
							psb.append("new Class[]{"+parameterTypes[0].getName()+".class");
							for (int i=1;i<parameterTypes.length;i++) {
								psb.append(","+parameterTypes[i].getName()+".class");
							}
							psb.append("}");
						}
						//method.getModifiers();可以获取修饰符的int值,下面偷懒了 统一写成public
						sb.append("public "+method.getReturnType().getName() +" "+method.getName()+"(");
						for (int i =0;i<parameterTypes.length;i++) {
							if(i==parameterTypes.length-1) {
								sb.append(parameterTypes[i].getName()+" arg"+i);
								break;
							}
							sb.append(parameterTypes[i].getName()+" arg"+i+",");
						}
						sb.append("){");
					
						//方法体 实际上调用的是invocationhandler中的方法
						sb.append("try{");
						//将method对象传入到invocationHandler.invoke();中
						if(parameterTypes.length>0) {
							sb.append("Object obj = invocationHandler.invoke(this,"+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+psb.toString()+")");
						} else {
							sb.append("Object obj = invocationHandler.invoke(this,"+clazz.getName()+".class.getMethod(\""+method.getName()+"\")");
						}
						for (int i =0;i<parameterTypes.length;i++) {
							sb.append(" ,arg"+i);
						}
						sb.append(");");
						//如果返回结果不是void 返回方法执行的结果
						if(!"void".equals(method.getReturnType().getName())) {
							sb.append("return ("+method.getReturnType().getName()+")obj;");
						}
						sb.append("}");
						sb.append("catch(Exception e){}");
						if(!"void".equals(method.getReturnType().getName())) {
							sb.append("return null;");
						}
						sb.append("}");
					
					}
				}
		sb.append("}");
		System.out.println(sb.toString());
		return sb.toString();
	}
}

二 核心代码2  在内存中编译源代码并加载class字节码文件

public class DynamicCompilerRAM {
    public static Class compiler(String javaSource,String className,String entireClassName,ClassLoader classLoader) throws Exception {
    	/*
         * 编译内存中的java代码
         * */
        // 1.将代码写入内存中
        StringWriter writer = new StringWriter(); // 内存字符串输出流
        PrintWriter out = new PrintWriter(writer);
        out.println(javaSource);
        out.flush();
        out.close();
        
        // 2.开始编译
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        JavaFileObject fileObject = new StringJavaObject(className, writer.toString());//
        CompilationTask task = javaCompiler.getTask(null, null, null, Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));
        boolean success = task.call();
        if (!success) {
            System.out.println("编译失败");
        }else{
            System.out.println("编译成功");
        }
       // URL[] urls = new URL[]{new URL("file:/" + "./bin/")};
        //URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class classl =classLoader.loadClass(entireClassName);
        return classl;
    }
}
三 测试效果

1 先准备一个接口和一个实现类

public interface Test{
	public void f();
	public void f2(String s);
	public String f3(String input);
}
public class TestProxy implements Test {
	private String name;
	public TestProxy(String name) {
		this.name = name;
	}
	@Override
	public void f() {
		System.out.println("我是被代理对象!"+name+"!");
	}

	@Override
	public void f2(String s) {
		System.out.println("我实现了基本的动态代理"+s);
	}
	@Override
	public String f3(String input) {
		return input;
	}
}
2 开始测试

public class Main {
	public static void main(String[] args) throws Exception{
		//测试代理
		TestProxy testProxy = new TestProxy("testProxy");
		Test t=(Test) MyProxy.newProxyInstance(testProxy.getClass().getClassLoader(), testProxy.getClass().getInterfaces(), new InvocationHandler() {
			@Override
			public Object invoke( Object obj,Method method, Object...args){
				try {
					System.out.println("方法执行前!");
					Object o = method.invoke(testProxy, args);//具体执行这个方法的任然是原来的对象
					//System.out.println(obj);
					System.out.println("方法执行后");
					return o;
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}
		});
		t.f();
		t.f2("哈哈");
		String s = t.f3("输入字符串");
		System.out.println(s);
	}
}


3 测试效果
编译成功
代理对象:com.colin.proxy.$proxy366712642@28feb3fa
方法执行前!
我是被代理对象!testProxy!
方法执行后
方法执行前!
我实现了基本的动态代理哈哈
方法执行后
方法执行前!
方法执行后
输入字符串
4 动态编译生成的代理对象源码

public class $proxy366712642 implements classaboutproxy.Test {
    private classaboutproxy.InvocationHandler invocationHandler;

    public $proxy366712642(classaboutproxy.InvocationHandler invocationHandler) {
        this.invocationHandler = invocationHandler;
    }

    public java.lang.String f3(java.lang.String arg0) {
        try {
            Object obj = invocationHandler.invoke(this,
                    classaboutproxy.Test.class.getMethod("f3",
                        new Class[] { java.lang.String.class }), arg0);
            return (java.lang.String) obj;
        } catch (Exception e) {
        }

        return null;
    }

    public void f() {
        try {
            Object obj = invocationHandler.invoke(this,
                    classaboutproxy.Test.class.getMethod("f"));
        } catch (Exception e) {
        }
    }

    public void f2(java.lang.String arg0) {
        try {
            Object obj = invocationHandler.invoke(this,
                    classaboutproxy.Test.class.getMethod("f2",
                        new Class[] { java.lang.String.class }), arg0);
        } catch (Exception e) {
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值