一看就懂RPC之反向代理
作者:黑白搬磚工
juejin.im/post/6844904116888535054
1.前言
系統(tǒng)開發(fā)已經(jīng)由單體服務(wù)轉(zhuǎn)向?yàn)橐粋€(gè)一個(gè)的微小服務(wù),微小服務(wù)的好處就是每個(gè)服務(wù)只需要關(guān)心自己內(nèi)部的業(yè)務(wù),當(dāng)需要相關(guān)業(yè)務(wù)數(shù)據(jù)的時(shí)候,就會(huì)面臨服務(wù)調(diào)用的問題,服務(wù)調(diào)用其實(shí)也好解決,可以使用java自帶的HttpURLConnection進(jìn)行遠(yuǎn)程服務(wù)的調(diào)用,也可以使用HttpClient或者是OkHttp這樣的第三方客戶端進(jìn)行遠(yuǎn)程服務(wù)調(diào)用,同樣也可以使用高性能遠(yuǎn)程調(diào)用框架Dubbo。
目前比較流行的微服務(wù)技術(shù)棧,可以使用基于Netty實(shí)現(xiàn)的Dubbo,或者使用基于Http實(shí)現(xiàn)的SpringCloud,不管哪種技術(shù),為了實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用的便利性,使開發(fā)者只需要關(guān)注業(yè)務(wù)本身,而不需要關(guān)注調(diào)用細(xì)節(jié),都采取了反向代理技術(shù)。反向代理技術(shù)在實(shí)現(xiàn)服務(wù)間透明調(diào)用起到了非常重要作用,既然重要,那么就有必要和大家一起來溫習(xí)一下反向代理技術(shù)。
2.反向代理
2.1 代理的作用
代理的作用就是增強(qiáng)目標(biāo)方法的能力,比如最常見的事務(wù)、Aop都是基于代理來實(shí)現(xiàn)的。當(dāng)需要增強(qiáng)目標(biāo)方法的能力,并且這些能力都是相同的,那么就可以采取代理的方式進(jìn)行實(shí)現(xiàn)。
2.2 代理的分類
靜態(tài)代理:靜態(tài)代理需要為每個(gè)被代理的類創(chuàng)建一個(gè)代理類,當(dāng)被代理的類過多的時(shí)候,就會(huì)導(dǎo)致代理類的增多,不便于維護(hù)。動(dòng)態(tài)代理:動(dòng)態(tài)代理不需要為每個(gè)被代理的類創(chuàng)建一個(gè)代理類,只需要一個(gè)全局的代理類,在需要的時(shí)候動(dòng)態(tài)生成,便于維護(hù)。
2.3 靜態(tài)代理

如圖可以看到被代理類實(shí)現(xiàn)的接口和被代理類其實(shí)就是我們開發(fā)的業(yè)務(wù)接口和業(yè)務(wù)接口實(shí)現(xiàn)類,在需要代理的情況下,代理類也要實(shí)現(xiàn)被代理類實(shí)現(xiàn)的接口,接下來我們來看一下代碼的實(shí)現(xiàn)。
2.3.1 被代理類實(shí)現(xiàn)的接口
public?interface?HelloService?{
????void?hello();
}
2.3.2 被代理類
public?class?HelloServiceImpl?implements?HelloService?{
????public?void?hello()?{
????????System.out.println("你吃了嘛?");
????}
}
2.3.3 代理類
public?class?HelloServiceStaticProxy?implements?HelloService?{
????private?HelloService?helloService;
????public?HelloServiceStaticProxy(HelloService?helloService)?{
????????this.helloService?=?helloService;
????}
????public?void?hello()?{
????????System.out.println("你好,我是小王!");
????????this.helloService.hello();
????????System.out.println("好的,下次家里聊!");
????}
}
2.3.4 測試
@Test
public?void?staticProxy()?{
????HelloServiceStaticProxy?helloServiceStaticProxy?=?new?HelloServiceStaticProxy(new?HelloServiceImpl());
????helloServiceStaticProxy.hello();
}
你好,我是小王!
你吃了嘛?
好的,下次家里聊!
2.3.5 小結(jié)
靜態(tài)代理要求代理類和被代理類實(shí)現(xiàn)同一個(gè)接口,代理對象需要持有被代理的目標(biāo)對象,在代理對象實(shí)現(xiàn)接口方法前后添加增強(qiáng)邏輯并調(diào)用目標(biāo)對象方法。
搜索Java知音,回復(fù)“后端面試”,送你一份面試寶典.pdf
2.4 動(dòng)態(tài)代理
2.4.1 動(dòng)態(tài)代理實(shí)現(xiàn)技術(shù)
基于jdk實(shí)現(xiàn)基于Cglib實(shí)現(xiàn)
2.4.2 基于jdk實(shí)現(xiàn)
2.4.2.1 創(chuàng)建代理類,實(shí)現(xiàn)InvocationHandler接口
public?class?JdkDynamicProxy?implements?InvocationHandler?{
????private?Object?target;
????public?JdkDynamicProxy(Object?target)?{
????????this.target?=?target;
????}
????public?Object?getTarget()?{
????????return?target;
????}
????public?void?setTarget(Object?target)?{
????????this.target?=?target;
????}
????@Override
????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
????????System.out.println("你好,我是小王!");
????????Object?result?=?method.invoke(target,?args);
????????System.out.println("好的,下次家里聊!");
????????return?result;
????}
}
2.4.2.2 創(chuàng)建代理工廠類
public?class?JdkDynamicProxyFactory?{
????private?JdkDynamicProxy?jdkDynamicProxy;
????public?JdkDynamicProxyFactory(JdkDynamicProxy?helloServiceJdkDynamicProxy)?{
????????this.jdkDynamicProxy?=?helloServiceJdkDynamicProxy;
????}
????public?Object?getProxy()?{
????????Object?target?=?jdkDynamicProxy.getTarget();
????????return?Proxy.newProxyInstance(jdkDynamicProxy.getClass().getClassLoader(),?target.getClass().getInterfaces(),?jdkDynamicProxy);
????}
}
2.4.2.3 測試
@Test
public?void?test()?{
????JdkDynamicProxy?jdkDynamicProxy?=?new?JdkDynamicProxy(new?HelloServiceImpl());
????JdkDynamicProxyFactory?proxyFactory?=?new?JdkDynamicProxyFactory(jdkDynamicProxy);
????HelloService?proxy?=?(HelloService)?proxyFactory.getProxy();
????proxy.hello();
}
你好,我是小王!
你吃了嘛?
好的,下次家里聊!
2.4.3 基于cglib實(shí)現(xiàn)
2.4.3.1 創(chuàng)建代理類,實(shí)現(xiàn)MethodInterceptor接口
public?class?CglibDynamicProxy?implements?MethodInterceptor?{
????private?Object?target;
????public?CglibDynamicProxy(Object?target)?{
????????this.target?=?target;
????}
????public?Object?getTarget()?{
????????return?target;
????}
????public?void?setTarget(Object?target)?{
????????this.target?=?target;
????}
????@Override
????public?Object?intercept(Object?o,?Method?method,?Object[]?args,?MethodProxy?methodProxy)?throws?Throwable?{
????????System.out.println("你好,我是小王!");
????????Object?result?=?method.invoke(target,?args);
????????System.out.println("好的,下次家里聊!");
????????return?result;
????}
}
2.4.3.2 創(chuàng)建代理工廠類
public?class?CglibDynamicProxyFactory?{
????private?CglibDynamicProxy?cglibDynamicProxy;
????public?CglibDynamicProxyFactory(CglibDynamicProxy?cglibDynamicProxy)?{
????????this.cglibDynamicProxy?=?cglibDynamicProxy;
????}
????public?Object?getProxy()?{
????????Enhancer?enhancer?=?new?Enhancer();
????????enhancer.setInterfaces(cglibDynamicProxy.getTarget().getClass().getInterfaces());
????????enhancer.setCallback(cglibDynamicProxy);
????????return?enhancer.create();
????}
}
2.4.3.3 測試
@Test
public?void?test()?{
????CglibDynamicProxy?cglibDynamicProxy?=?new?CglibDynamicProxy(new?HelloServiceImpl());
????CglibDynamicProxyFactory?proxyFactory?=?new?CglibDynamicProxyFactory(cglibDynamicProxy);
????HelloService?proxy?=?(HelloService)?proxyFactory.getProxy();
????proxy.hello();
}
你好,我是小王!
你吃了嘛?
好的,下次家里聊!
2.4.4 jdk動(dòng)態(tài)代理與cglib動(dòng)態(tài)代理的區(qū)別
jdk動(dòng)態(tài)代理不需要引入第三方包,需要實(shí)現(xiàn)InvocationHandler接口,要求被代理對象必須實(shí)現(xiàn)接口
cglib動(dòng)態(tài)代理需要引入第三方包,需要實(shí)現(xiàn)MethodInterceptor接口,被代理對象可以實(shí)現(xiàn)接口,也可以不實(shí)現(xiàn)接口
3. 總結(jié)
今天和大家一起溫習(xí)了一下代理的相關(guān)技術(shù),代理分為:靜態(tài)代理和動(dòng)態(tài)代理,動(dòng)態(tài)代理的實(shí)現(xiàn)技術(shù)有:基于jdk來實(shí)現(xiàn)和基于cglib來實(shí)現(xiàn),cglib可以針對沒有實(shí)現(xiàn)接口的目標(biāo)對象進(jìn)行代理。代理技術(shù)是后續(xù)篇章的講解的基石,只有掌握代理技術(shù),才能更好的去學(xué)習(xí)、實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用,希望你能牢牢掌握該門技術(shù),可以讓自己在后續(xù)的篇章中無任何絆腳石。
