手敲JDK动态代理实现
上一篇文章其实已经把动态代理底层实现讲的很清楚的,这篇想要直接上代码的,毕竟实现的步骤其实是差不多的。
https://www.jianshu.com/p/72d1448a29f0
步骤如下:
1.新建一个XXXProxy类,然后获取一个代理类实例。
2.新建一个XXXInvocationHandle抽象接口,还有invoke方法。
3.新建一个类加载器,这样根据双亲委派机制,可以加载我们的代理类,每个类在JVM中都有各自的类加载器的,JVM本身有提供,我们也可以自己定义。
4.重新newInstance方法,里面的生成步骤如下:
// 1.动态生成源代码.java文件
// 2.把java文件输出到磁盘
// 3.把生成的.java文件编译成
//获取系统编译器
//4.编译生成的.class文件加载到jvm中来
/编译完成后删除
// 5.返回字节码重组以后新的代理对象。
最后测试。
直接撸代码了哈。
ZXYProxy类如下:
public class ZXYProxy{
public static final String ln = "\r\n";
public static Object newProxyInstance(ZXYClassLoader classLoader,Class<?> [] interfaces,ZXYInvocationHandle h){
try {
// 1.动态生成源代码.java文件
String src = generateSrc(interfaces);
// 2.把java文件输出到磁盘
String path = ZXYProxy.class.getResource("").getPath();
System.out.println(path);
File f = new File(path + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
// 3.把生成的.java文件编译成
//获取系统编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
Iterable javaFileObjects = standardFileManager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,standardFileManager,null,null,null,javaFileObjects);
task.call();
standardFileManager.close();
//4.编译生成的.class文件加载到jvm中来
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor constructor = proxyClass.getConstructor(ZXYInvocationHandle.class);
//编译完成后删除
f.delete();
// 5.返回字节码重组以后新的代理对象。
return constructor.newInstance(h);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces){
StringBuffer sb=new StringBuffer();
sb.append("package com.zxy.test.gupao.tom.proxy.custom;" + ln);
sb.append("import com.zxy.test.gupao.tom.proxy.staticed.Person;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("ZXYInvocationHandle h;" + ln);
sb.append("public $Proxy0(ZXYInvocationHandle h) {" + ln);
sb.append("this.h = h;" + ln);
sb.append("}" + ln);
for(Method m : interfaces[0].getMethods()){
sb.append("public "+ m.getReturnType()+" "+ m.getName() +"() {"+ ln);
sb.append("try {"+ln);
sb.append("Method m = "+interfaces[0].getName() +".class.getMethod(\""+m.getName()+"\",new Class[]{});"+ ln);
sb.append("this.h.invoke(this,m,null);"+ln);
sb.append("}catch(Throwable e){"+ln);
sb.append("e.printStackTrace();"+ln);
sb.append("}" + ln);
sb.append("}");
}
sb.append("}"+ln);
return sb.toString();
}
}
ZXYInvocationHandle:
``java
public interface ZXYInvocationHandle {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
接下来是类加载器
ZXYClassLoader
```java
public class ZXYClassLoader extends ClassLoader{
private File classPathFile;
public ZXYClassLoader(){
String classPath = ZXYClassLoader.class.getResource("").getPath();
this.classPathFile=new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = ZXYClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File file = new File(classPathFile, name.replaceAll("\\.", "/")+".class");
//字节读取
if(file.exists()){
FileInputStream in=null;
ByteArrayOutputStream out=null;
try{
in=new FileInputStream(file);
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(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
然后是媒婆代理类:
public class CustomerMeiPo implements ZXYInvocationHandle{
private Person target;
public Object getInstance(Person target)throws Exception{
this.target=target;
Class<? extends Person> aClass = target.getClass();
return ZXYProxy.newProxyInstance(new ZXYClassLoader(),aClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
method.invoke(this.target,args);
System.out.println("如果合适的话,就准备办事");
return null;
}
}
还有一个代理类的接口,没什么哈。
public interface Person {
public void findLove();
public void zufangzi();
public void buy();
public void findJob();
//......
}
这是被代理类。
public class XieMu implements Person {
@Override
public void findLove(){
System.out.println("高富帅");
System.out.println("身高180cm");
System.out.println("胸大,6块腹肌");
}
@Override
public void zufangzi() {
System.out.println("租房子");
}
@Override
public void buy() {
System.out.println("买东西");
}
@Override
public void findJob() {
System.out.println("月薪20K-50k");
System.out.println("找工作");
}
}
最后,终于结束了。测试类:
public class ZXYProxyTest {
public static void main(String[] args) {
try {
Person obj = (Person)new CustomerMeiPo().getInstance(new XieMu());
System.out.println(obj.getClass());
obj.findLove();
//打印出来
byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
os.write(bytes);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果如下:
![](https://img.haomeiwen.com/i4017523/8523e856abbe74b4.png)
还差一点,去我们的E盘看看,已经编译好一个代理类了。跟JDK实现的是一样的。
![](https://img.haomeiwen.com/i4017523/c75a1b3eba6d6d3f.png)
ok,撸完收工!
然后如果没感觉我这篇文章都在贴代码,可以看我的上一篇文章。详细讲解了JDK是怎么实现了。步骤是一样一样的。
可能有的看到了,我是看视频学习的,嗯,不过每行代码还有源码分析都是自己去分析的。每行都是自己敲的,整理分享不易,希望大家多多支持。
感谢您阅读我的文章,如果满意可以帮我点赞,谢谢哈。
如果对文章部分还有什么见解或者疑惑,可以私信评论我,欢迎技术讨论。如果需要获取完整的文件资源,可以加我微信z985085305,获取我整理的全套笔记。
思想的碰撞最能促进技术的进步哦。