上篇文章的JDK动态代理分析,我们知道了动态代理原理,接下来将实现一个简易版本的动态代理
大概思路
这里为了简单实现,不引入字节码技术了,直接使用将源代码编译成class文件,再通过ClassLoader加载生成的class文件。
- 动态生成源代码java文件
- Java文件输出磁盘
- 把生成的.java文件编译成.class文件
- 将编译生成的.class文件加载到JVM中来
- 返回字节码重组以后的新的代理对象
代码实现
被代理的业务代码
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