最近看动态代理和aop,对一些问题有一些疑惑和自己的理解,希望大佬能看看我说的哪里有问题,给我指正,欢迎讨论
//调用该方法Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myInvocationHandler);}
//返回一个代理类的对象,实现第一步,而我们自己写
的InvocationHandler的接口实现类,看似和静态代理的代理类比较像,
//但在动态代理中他的作用并不太符合代理类,只是我们写的与动态代理无关的
切面部分,比如我们自定义的一些“不动态的写死的”业务流程,
//更像是一个最终产生的代理类的展示效果,这也很顺理成章,因为看过源码后,
发现真正要自己写出动态代理类真的太难了,所以java给你准备好了,
你只需要写个handler就行
//然后作为一个参数传入Proxy.newProxyInstance来创建真正的代理类
//实际上代理类是Proxy.newProxyInstance给我们生成的,
//这个对象是由jvm动态创建的,没有java源文件的实际存储,
而是jvm根据传入的参数替我们临时写出的java代码然后用传入的classloader装载,
生成class字节码文件,类型名$Proxy0,反正名字就是这样起的,是proxy的子类,
//在后面实际使用时通常会强转,又因为$Proxy0实现了所有接口了,
自然也可以强转成功,向下转型为其中的某一个接口的实现类
//这个$Proxy0对象也就是给我们实际生成的代理类实例里有如下细节:
也解决了我的疑惑:
//为什么jvm给我返回的代理类对象就可以调用被代理类的方法然后和我
传入的handler里重写的方法关联起来的?
//首先它遍历了并且实现了传入接口的所有方法:
具体源码细节可以这样理解:
主要还是用了反射把被代理类实现的接口的那些方法给一一找出来并且
和代理类关联:操作如下:
//$Proxy0对象定义了一堆method类型的属性,通过静态代码块
//{利用反射,返回所有的接口那些方法然后全部赋值给这些属性,
比如用for循环:
//先通过getMethods把所有接口的方法名全部遍历出来,
然后再用接口.class.getMethod(方法名)把所有方法取出来并赋值}
//进行初始化,从而和被代理类的那些方法一一对应,比如被代理类实现了
衣服加工厂的produce()方法,那就可以通过上述反射操作得到方法名,
然后得到method类型的produce,
//然后将它写入代理类的produce方法中h.invoke的第二个参数里,
从而实现了返回的代理类对象可以调用被代理类实现的接口的那些方法(接口),
并且在方法体内部,实际执行了被代理类(对象)的同名方法
//其中这个h是代理类里一个InvocationHandler类型的属性InvocationHandler h,
一切都是顺理成章
//在调用newProxyInstance创建时,会把我们写好并且传入
的MyInvocationHandler赋值给他,从而就产生了关联,或者说
可以对它进行使用了
//接下来实现接口中的方法时,方法的方法体内部都是调用了它的invoke方法
传入同名方法也就是第二个参数来实现的
//也就是调用MyInvocationHandler.invoke(Object proxy, Method method, Object[] args),
//注意这里的第一个参数:object proxy也就是代理类的对象,
在$Proxy0源码里是this,
//因为该方法是在$Proxy0类里的同名方法里写着的,
所以this正好就是实际同名方法的调用者也就是代理类的实例$Proxy0对象,
而不是handler
//
//第一个参数看似无用,但是通过查阅资料,它的作用是可以通过return
返回生产出来的该代理类对象,因为整个过程中,是jvm动态编译的没有留下源
文件,所以我们并不知道代理类实例的具体细节,甚至不知道是什么类型,
有什么结构等等
//就像无源之水一样,我们实际并没有自己给他传这些参数,传参数的过程
都在proxy里封装起来了,所以返回它我们就可以通过反射看一看到底造出来的
对象有什么结构,并且还能因此重复使用它
例如proxy.method().method().method()
//说完之后发现一个很有意思的事情:这些源代码都是上网查阅的,
他们通过反编译class文件得到的源码,这些源码不是我写的,而是jvm自己
动态编写出来的那么:
// 为什么这些东西看起来很顺理成章,但是却没有java源代码存留,
就好像我会写代码让jvm编译运行,结果它自己也会写代码,
直接绕过我写完之后编译执行了,后来上网查阅发现一篇博客,感觉很有道理,
// 这些代码好像是jvm利用我们传入的参数,然后字符串拼串把Java代码“模仿”
出来了(就类似sql语句注入),他把这些代码都看成是字符串就没有那么多
语法限制了,要不然没人告诉它,他自己怎么写这些代码比如属性,方法体等等
他咋可能自己写出这些结构来的
//然后利用io流写入搞出来一个临时的java文件即可,当然这是我看那篇博客
是这样写的,因为我看了反编译源码感觉顺理成章,
但是比如源码中静态代码块那里为什么直接就classforname(类名)了,这些参数从哪来的,他怎么知道的,代码里面都没体现,感觉不太理解