资讯专栏INFORMATION COLUMN

【好好面试】学完Aop,连动态代理的原理都不懂?

Keven / 3109人阅读

摘要:总结动态代理的相关原理已经讲解完毕,接下来让我们回答以下几个思考题。

【干货点】 此处是【好好面试】系列文的第12篇文章。
文章目标主要是通过原理剖析的方式解答Aop动态代理的面试热点问题,通过一步步提出问题和了解原理的方式,我们可以记得更深更牢,进而解决被面试官卡住喉咙的情况。
问题如下

SpringBoot默认代理类型是什么

为什么不用静态代理

JDK动态代理原理

CGLIB动态代理原理

JDK动态代理和CGLIB动态代理的区别

为什么CGLIB不能像JDK代理那样,直接使用反射触发目标函数

为什么CGLIB代理可以直接对类进行代理,而JDK代理却一定要实现接口

大前提

该文章是必须要懂的SpringAop系列的最后一篇文章,第一篇文章是你必须要懂的Spring-Aop之应用篇,第二篇文章是你必须要懂的Spring-Aop之源码跟踪分析Aop,最后一篇文章我们将会揭露Aop的原理,也就是动态代理。希望看完这最后一篇文章,大家对SpringAop都有一个全面的掌握,不管面试官如何问,都可以屌回去 ━━( ̄ー ̄*|||━━

温馨提示:前面没看的最好点击浏览下!!!
说个坑爹的事

大家都知道,我有个习惯,在动手写一篇文章之前会先将该文章相关的资料仔细琢磨一遍,然后再结合源码再调试一遍,结果,说好的

看源码也确实是

源码确实有进行了是否是接口的判断,但是问题来了,我调试的时候发现无论代理类是否有接口,最终都会被强制使用CGLIB代理,没办法,只能翻看SpringBoot的相关文档,最终发现原来SpringBoot从2.0开始就默认使用Cglib代理了,好家伙,怪不得我调试半天找不到原因。

那么如何解决呢?肯定是通过配置啦,按照如下配置即可

在application.properties文件中配置 spring.aop.proxy-target-class=false

即可。

【划重点】 曾经遇见过面试官问,SpringBoot默认代理类型是什么?看完该篇文章,我们就可以果断的回答是Cglib代理了。通过调试代码发现的规则,我想我这辈子都不会忘记这个默认规则。
动态代理原理剖析 什么是代理

简单来说,就是在运行的时候为目标类动态生成代理类,而在操作的时候都是操作代理类,代理模式有个显而易见的好处,那便是可以在不改变对象方法的情况下对方法进行增强。试想下,我们在你必须要懂的Spring-Aop之应用篇有提到使用Aop来做权限认证,如果不用Aop,那么我们就必须要为所有需要权限认证的方法都加上权限认证代码,听起来就觉得蛋疼,你觉得对不对?

为什么不用静态代理

静态代理类不是说不可以用,如果只有一个类需要被代理,那么自然可以用,如
这是在你必须要懂的Spring-Aop之应用篇使用的一个例子类,该类的作用只是打印出我要买东西。

代理类如下

可以看到这个BuyProxy代理类只是塞了一个IBuyServcie接口进行,而且自身也实现了接口IBuyService,而在buyItem方法被调用的时候会先做自己的操作,再调用塞进去的接口的buyItem方法。
测试类很简单,如下

运行后很自然而然的打印出

静态代理就是简单,但是弊端也很明显,如果有多个类都需要同样的代理,都实现了同样的接口,那么如果使用静态代理的话,我们就要构造多个Proxy类,就会造成类爆炸
而使用了Aop后,也就是动态代理后,便可以一次性解决该问题了,具体可以看你必须要懂的Spring-Aop之应用篇中的操作方法。

JDK动态代理原理

这里给出一个JDK动态代理的demo
首先给出一个简单的业务类,Hello类和接口

真正实现了类的代理功能的其实就是这个实现了接口InvocationHandler的JdkProxy类

我们可以看到其中必须实现的方法是invoke,可以看到invoke方法的参数带有Method对象,这个就是我们的目标Method,现在我们的目的就是要在这个Method在被调用前后实现我们的业务,可以看到在method.invoke反调前后实现了before和after业务。

这里再给出一个Main测试类,作用是取得Hello的代理类,然后调用其中的say方法。

运行结果如下

原理很简单 在JdkProxyMain中hello调用say的时候,由于Hello已经被“代理”了,所以在调用say函数的时候其实是调用JdkProxy类中的invoke函数,而在invoke函数中先是实现了before函数才实现Object result = method.invoke(target, args),这一句其实是调用say函数,而后才实现after函数,于是这样就可以不必在改动目标类的前提下实现代理了,并且不会像静态代理那样导致类爆炸。

CGLIB动态代理原理

先给出一个Cglib动态代理的demo

【思考题一】为什么CGLIB代理可以直接对类进行代理,而JDK代理却一定要实现接口呢?答案见问末!!!

核心类是实现了MethodInterceptor的CGlibProxy类

可以看到其中实现了方法intercept,先是在目标函数被调用前实现自己的业务,比如before()和after(),之后再通过 proxy.invokeSuper(obj, args) 触发目标函数。

【思考题二】为什么这里不像JDK代理那样,直接使用反射[method.invoke(target, args)]触发目标函数?答案见问末!!!

最后给出入口类

最后给出运行类,运行类如下

可以看到运行结果

原理很简单 在CglibProxyMain中hello调用say的时候,由于Hello已经被“代理”了,所以在调用say函数的时候其实是调用CGlibProxy类中的intercept函数。

总结

动态代理的相关原理已经讲解完毕,接下来让我们回答以下几个思考题。

「思考解惑一」为什么CGLIB代理可以直接对类进行代理,而JDK代理却一定要实现接口呢?
可以从我们上面的例子看出,在JdkProxy类中取得代理类的方式是
(T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this)
而在CGlibProxy类中取得代理类的方式是
(T) Enhancer.create(cls, this)
两种取得代理类的方式不同,导致了一个需要实现接口,一个不需要。

「思考解惑二」为什么这里不像JDK代理那样,直接使用反射[method.invoke(target, args)]触发目标函数?
首先要进行反射触发函数,要取得对应的method,以及该method所属对象,也就是target,再次是args方法参数,而我们看下调试界面

可以从界面看到,目标对象obj并不是Hello对象,二是被CGLIB代理过的对象,因此无法像JDK代理那样直接通过反射搞定。

最后的最后

鉴于很多朋友都来找我聊《好好面试》相关的问题,本人也比较忙,无法一一应答,为此在此创建了一个微信群,有兴趣的可以加入,只聊面试和技术相关。

如果过期了,可以在关注公众号,在公众号上喊我一声,说要加群即可。

[好好面试] 系列文推荐:

你必须要懂的Spring-Aop之源码跟踪分析Aop
你必须要懂的Spring-Aop之应用篇
你所不知道的HelloWorld背后的原理
连引用都答不上,凭什么说你是Java服务端开发
你是否了解Spring中bean的生命周期呢?
开发必学,io&nio
你所不知道的HelloWorld背后的原理
如何基于spring动态注册bean
拓展spring组件之自定义标签
基于spring实现事件驱动
Java日常干货
Java&Spring系列笔记

[gomicro微服务] 系列文推荐:

go微服务系列之一

go微服务系列之二

go微服务系列之三

go微服务系列之四

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75802.html

相关文章

  • Java开发 大厂面试整理

    摘要:用户态不能干扰内核态所以指令就有两种特权指令和非特权指令不同的状态对应不同的指令。非特权指令所有程序均可直接使用。用户态常态目态执行非特权指令。 这是我今年从三月份开始,主要的大厂面试经过,有些企业面试的还没来得及整理,可能有些没有带答案就发出来了,还请各位先思考如果是你怎么回答面试官?这篇文章会持续更新,请各位持续关注,希望对你有所帮助! 面试清单 平安产险 飞猪 上汽大通 浩鲸科...

    Scorpion 评论0 收藏0
  • 好好面试】手把手调试,教你分析Spring-Aop

    摘要:思考之所以会选择为切入点,是因为通过命名可以看出这是用来构建代理强化对象的地方,并且由于是先将目标类加载到内存中,之后通过修改字节码生成目标类的子类,因此我猜测强化是在目标类实例化后触发的时候进行的。 【干货点】 此处是【好好面试】系列文的第11篇文章。看完该篇文章,你就可以了解Spring中Aop的相关使用和原理,并且能够轻松解答Aop相关的面试问题。更重要的是,很多人其实一看源码就...

    aervon 评论0 收藏0
  • 好好面试】你必须要懂Spring-Aop

    摘要:干货点此处是好好面试系列文的第篇文章。而这也是出现的原因,没错,就是被设计出来弥补短板的。运行结果如下运行结果可想而知,的通过验证,的失败。 【干货点】此处是【好好面试】系列文的第10篇文章。看完该篇文章,你就可以了解Spring中Aop的相关使用和原理,并且能够轻松解答Aop相关的面试问题。 在实际研发中,Spring是我们经常会使用的框架,毕竟它们太火了,也因此Spring相关的知...

    honhon 评论0 收藏0
  • Java深入-框架技巧

    摘要:从使用到原理学习线程池关于线程池的使用,及原理分析分析角度新颖面向切面编程的基本用法基于注解的实现在软件开发中,分散于应用中多出的功能被称为横切关注点如事务安全缓存等。 Java 程序媛手把手教你设计模式中的撩妹神技 -- 上篇 遇一人白首,择一城终老,是多么美好的人生境界,她和他历经风雨慢慢变老,回首走过的点点滴滴,依然清楚的记得当初爱情萌芽的模样…… Java 进阶面试问题列表 -...

    chengtao1633 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<