JDK动态代理实现

上篇文章的JDK动态代理分析,我们知道了动态代理原理,接下来将实现一个简易版本的动态代理

大概思路
这里为了简单实现,不引入字节码技术了,直接使用将源代码编译成class文件,再通过ClassLoader加载生成的class文件。

  1. 动态生成源代码java文件
  2. Java文件输出磁盘
  3. 把生成的.java文件编译成.class文件
  4. 将编译生成的.class文件加载到JVM中来
  5. 返回字节码重组以后的新的代理对象
代码实现

被代理的业务代码

public interface IPersonService {
	void sayHello();
}

public class PersonServiceImpl implements IPersonService {
	@Override
	public void sayHello() {
		System.out.println("hello to you");
	}
}

自定义InvocationHandler,与JDK保持一致

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

实现自定义InvocationHandler,加入代理逻辑

public class MyInvocationHandlerImpl implements MyInvocationHandler {
	private IPersonService service;
	
	public MyInvocationHandlerImpl(IPersonService service) {
		this.service = service;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("==>");
		System.out.println("====>");
		Object invoke = method.invoke(service, args);
		System.out.println("======>");
		System.out.println("========>");
		return invoke;
	}
}

核心代理类逻辑

public class MyProxy {
	public static Object newProxyInstance(MyClassLoader myClassLoader, Class<?>[] interfaces,
			MyInvocationHandler h) {
		
		try {
			// 1. 动态生成源代码.java文件
			String generateStr = generateStr(interfaces);
			
			// 2.Java文件输出磁盘
			String path = MyProxy.class.getResource("").getPath();
			File file = new File(path + "$MyProxy.java");
			FileWriter fw = new FileWriter(file);
			fw.write(generateStr);
			fw.flush();
			fw.close();
		
			// 3.把生成的.java文件编译成.class文件
			JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
			StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
			Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(file);
			CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, iterable);
			task.call();
			manager.close();
			
			// 4.将编译生成的.class文件加载到JVM中来
			Class<?> proxyClass = myClassLoader.findClass("$MyProxy");
			Constructor<?> constructor = proxyClass.getConstructor(MyInvocationHandler.class);
			
			// 5.返回字节码重组以后的新的代理对象
			Object newInstance = constructor.newInstance(h);
			return newInstance;
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}

	private static final String rn = "\r\n";
	
	private static String generateStr(Class<?>[] interfaces) {
		StringBuffer sb = new StringBuffer();
		sb.append("package priv.dengjili.spring.design.day01.custom;" + rn);
		sb.append("import java.lang.reflect.Method;" + rn);
		sb.append("public final class $MyProxy implements " + interfaces[0].getName() + " {" + rn);
		
		sb.append("MyInvocationHandler h;" + rn);
		
		sb.append("public $MyProxy(MyInvocationHandler h) {" + rn);
		sb.append("this.h = h;" + rn);
		sb.append("}" + rn);

		for (Method method : interfaces[0].getMethods()) {
			sb.append("public " + method.getReturnType().getName() + " " + method.getName() + "() {" + rn);
			sb.append("try {" + rn);
			sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[0]);" + rn);
			sb.append("this.h.invoke(this, m, null);" + rn);
			sb.append("} catch (Exception e) {" + rn);
			sb.append("e.printStackTrace();" + rn);
			sb.append("} catch (Throwable e) {" + rn);
			sb.append("e.printStackTrace();" + rn);
			sb.append("}" + rn);
			sb.append("}" + rn);
		}

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

ClassLoader实现,从硬盘中加载字节码重组后的class

public class MyClassLoader extends ClassLoader {
	
	private File file;
	
	public MyClassLoader() {
		String path = ClassLoader.getSystemClassLoader().getResource("").getPath();
		this.file = new File(path);
	}

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

测试类

public class MyProxyTest {
	public static void main(String[] args) {
		IPersonService service = new PersonServiceImpl();
		MyInvocationHandler h = new MyInvocationHandlerImpl(service);
		IPersonService proxyService = (IPersonService) MyProxy.newProxyInstance(new MyClassLoader(), service.getClass().getInterfaces(), h);
		proxyService.sayHello();
	}
}

测试结果

==>
====>
hello to you
======>
========>
上述实现优化,无临时文件生成编译

参考:https://blog.csdn.net/dengjili/article/details/106676567

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值