spring用代理类包裹切面,吧他们织入到Spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,然调用者对目标类的调用都先变成伪装类,伪装类这就先执行了切面,再把调用转发给真正的目标bean。
现在可以自己想一想,怎么搞出来这个伪装类,才不会被调用者发现(过JVM的检查,JAVA是强类型检查,哪里都要检查类型)。
1)实现和目标类相同的接口。
我也实现和你一样的接口,反正上层都是接口级别的调用,这样我就伪装成了和目标类一样的类(实现了同意接口,咱是兄弟了),也就逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring采用运行时),伪装类(代理类)就变成了接口的真正实现,二他里面包裹了真实的那个目标类,最后实现具体功能的还是目标类,只是不过伪装在之前干了点事情(写日志,安全检查,事物等)。
这就好比一个人让你办事,每次这个时候,你弟弟就会出来,当然他分不出来了,以为是你,你这个弟弟虽然办不了这个事,但是她知道你能办,所以就答应下来了,并且收了点礼物(写日志),收完礼物了,给把事给人家办了啊,所以你弟弟又找你这个哥哥来了,最后把这事办了还是你自己。但是你自己并不知道你弟弟已经收了礼物了,你只是专心把这件事做好。
顺着这个思想,要是本身这个类就没实现一个接口呢,你怎么伪装我,我就压给没有机会让你搞出这个双胞胎弟弟,那么就用第2种代理方式,创建一个目标类的子类,生个儿子,让儿子伪装我。
2)生成子类调用。
这次用子类来做伪装,当然这样也能逃过JVM的强类型检查,我继承的吗,当然查不出来了,子类重写了目标类的所有方法,当然在这些重写的方法中,不仅实现了目标类的功能,还在这些功能之前,实现了一些其他的(写日志,安全检查,事物等)。
这次的对比就是,儿子先从爸爸那儿把本事都学会了,所有人都找儿子办事,但是儿子每次办和爸爸同样的事之前,都要收点小礼物(写日志),然后才去办真正的事。当然爸爸是不知道儿子这么干的了。这里就有事情要说,某些本事是爸爸独有(final的),儿子学不会,学不了就办不了这个事,办不了这个事情,自然就不能收人家的礼物了。
前一种兄弟模式,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把这些接口的任何调用都转发到目标类。
后一种父子模式,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。
相比之下,还是兄弟模式好一些,她能更好的实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应该当做一种例外。
(转 https://www.cnblogs.com/lihuidu/p/5802611.html)