亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java的三種代理模式簡(jiǎn)述

 更新時(shí)間:2021年09月08日 16:32:05   作者:閃客sun  
這篇文章主要簡(jiǎn)述Java的三種代理模式,java的代理模式主要包括靜態(tài)代理、動(dòng)態(tài)代理、Cglib代理,感興趣的小伙伴可以參考下面文章的具體內(nèi)容

一、代理模式是什么

代理模式是一種設(shè)計(jì)模式,簡(jiǎn)單說(shuō)即是在不改變?cè)创a的情況下,實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的功能擴(kuò)展。

比如有個(gè)歌手對(duì)象叫Singer,這個(gè)對(duì)象有一個(gè)唱歌方法叫sing()。

1 public class Singer{
2     public void sing(){
3         System.out.println("唱一首歌");
4     }  
5 }

假如你希望,通過(guò)你的某種方式生產(chǎn)出來(lái)的歌手對(duì)象,在唱歌前后還要想觀眾問(wèn)好和答謝,也即對(duì)目標(biāo)對(duì)象Singer的sing方法進(jìn)行功能擴(kuò)展。

1 public void sing(){
2     System.out.println("向觀眾問(wèn)好");
3     System.out.println("唱一首歌");
4     System.out.println("謝謝大家");
5 }  

但是往往你又不能直接對(duì)源代碼進(jìn)行修改,可能是你希望原來(lái)的對(duì)象還保持原來(lái)的樣子,又或許你提供的只是一個(gè)可插拔的插件,甚至你有可能都不知道你要對(duì)哪個(gè)目標(biāo)對(duì)象進(jìn)行擴(kuò)展。這時(shí)就需要用到j(luò)ava的代理模式了。網(wǎng)上好多用生活中的經(jīng)理人的例子來(lái)解釋“代理”,看似通俗易懂,但我覺(jué)得不適合程序員去理解。程序員應(yīng)該從代碼的本質(zhì)入手。

二、Java的三種代理模式

想要實(shí)現(xiàn)以上的需求有三種方式,這一部分我們只看三種模式的代碼怎么寫,先不涉及實(shí)現(xiàn)原理的部分。

1.靜態(tài)代理

 1 public interface ISinger {
 2     void sing();
 3 }
 4 
 5 /**
 6  *  目標(biāo)對(duì)象實(shí)現(xiàn)了某一接口
 7  */
 8 public class Singer implements ISinger{
 9     public void sing(){
10         System.out.println("唱一首歌");
11     }  
12 }
13 
14 /**
15  *  代理對(duì)象和目標(biāo)對(duì)象實(shí)現(xiàn)相同的接口
16  */
17 public class SingerProxy implements ISinger{
18     // 接收目標(biāo)對(duì)象,以便調(diào)用sing方法
19     private ISinger target;
20     public UserDaoProxy(ISinger target){
21         this.target=target;
22     }
23     // 對(duì)目標(biāo)對(duì)象的sing方法進(jìn)行功能擴(kuò)展
24     public void sing() {
25         System.out.println("向觀眾問(wèn)好");
26         target.sing();
27         System.out.println("謝謝大家");
28     }
29 }

測(cè)試

 1 /**
 2  * 測(cè)試類
 3  */
 4 public class Test {
 5     public static void main(String[] args) {
 6         //目標(biāo)對(duì)象
 7         ISinger target = new Singer();
 8         //代理對(duì)象
 9         ISinger proxy = new SingerProxy(target);
10         //執(zhí)行的是代理的方法
11         proxy.sing();
12     }
13 }

  總結(jié):其實(shí)這里做的事情無(wú)非就是,創(chuàng)建一個(gè)代理類SingerProxy,繼承了ISinger接口并實(shí)現(xiàn)了其中的方法。只不過(guò)這種實(shí)現(xiàn)特意包含了目標(biāo)對(duì)象的方法,正是這種特征使得看起來(lái)像是“擴(kuò)展”了目標(biāo)對(duì)象的方法。假使代理對(duì)象中只是簡(jiǎn)單地對(duì)sing方法做了另一種實(shí)現(xiàn)而沒(méi)有包含目標(biāo)對(duì)象的方法,也就不能算作代理模式了。所以這里的包含是關(guān)鍵。

  缺點(diǎn):這種實(shí)現(xiàn)方式很直觀也很簡(jiǎn)單,但其缺點(diǎn)是代理對(duì)象必須提前寫出,如果接口層發(fā)生了變化,代理對(duì)象的代碼也要進(jìn)行維護(hù)。如果能在運(yùn)行時(shí)動(dòng)態(tài)地寫出代理對(duì)象,不但減少了一大批代理類的代碼,也少了不斷維護(hù)的煩惱,不過(guò)運(yùn)行時(shí)的效率必定受到影響。這種方式就是接下來(lái)的動(dòng)態(tài)代理。

2.動(dòng)態(tài)代理(也叫JDK代理)

跟靜態(tài)代理的前提一樣,依然是對(duì)Singer對(duì)象進(jìn)行擴(kuò)展

 1 public interface ISinger {
 2     void sing();
 3 }
 4 
 5 /**
 6  *  目標(biāo)對(duì)象實(shí)現(xiàn)了某一接口
 7  */
 8 public class Singer implements ISinger{
 9     public void sing(){
10         System.out.println("唱一首歌");
11     }  
12 }

這回直接上測(cè)試,由于java底層封裝了實(shí)現(xiàn)細(xì)節(jié)(之后會(huì)詳細(xì)講),所以代碼非常簡(jiǎn)單,格式也基本上固定。

調(diào)用Proxy類的靜態(tài)方法newProxyInstance即可,該方法會(huì)返回代理類對(duì)象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
接收的三個(gè)參數(shù)依次為:

  • ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,寫法固定
  • Class<?>[] interfaces:目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,寫法固定
  • InvocationHandler h:事件處理接口,需傳入一個(gè)實(shí)現(xiàn)類,一般直接使用匿名內(nèi)部類

測(cè)試代碼

 1 public class Test{
 2     public static void main(String[] args) {
 3   Singer target = new Singer();
 4         ISinger proxy  = (ISinger) Proxy.newProxyInstance(
 5                 target.getClass().getClassLoader(),
 6                 target.getClass().getInterfaces(),
 7                 new InvocationHandler() {
 8                     @Override
 9                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
10                         System.out.println("向觀眾問(wèn)好");
11                         //執(zhí)行目標(biāo)對(duì)象方法
12                         Object returnValue = method.invoke(target, args);
13                         System.out.println("謝謝大家");
14                         return returnValue;
15                     }
16                 });
17         proxy.sing();
18     }
19 }

總結(jié):以上代碼只有標(biāo)黃的部分是需要自己寫出,其余部分全都是固定代碼。由于java封裝了newProxyInstance這個(gè)方法的實(shí)現(xiàn)細(xì)節(jié),所以使用起來(lái)才能這么方便,具體的底層原理將會(huì)在下一小節(jié)說(shuō)明。

缺點(diǎn):可以看出靜態(tài)代理和JDK代理有一個(gè)共同的缺點(diǎn),就是目標(biāo)對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口,加入沒(méi)有,則可以使用Cglib代理。

3.Cglib代理

前提條件:

  • 需要引入cglib的jar文件,由于Spring的核心包中已經(jīng)包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
  • 目標(biāo)類不能為final
  • 目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法
1 /**
2  * 目標(biāo)對(duì)象,沒(méi)有實(shí)現(xiàn)任何接口
3  */
4 public class Singer{
5 
6     public void sing() {
7         System.out.println("唱一首歌");
8     }
9 }

 1 /**
 2  * Cglib子類代理工廠
 3  */
 4 public class ProxyFactory implements MethodInterceptor{
 5     // 維護(hù)目標(biāo)對(duì)象
 6     private Object target;
 7 
 8     public ProxyFactory(Object target) {
 9         this.target = target;
10     }
11 
12     // 給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象
13     public Object getProxyInstance(){
14         //1.工具類
15         Enhancer en = new Enhancer();
16         //2.設(shè)置父類
17         en.setSuperclass(target.getClass());
18         //3.設(shè)置回調(diào)函數(shù)
19         en.setCallback(this);
20         //4.創(chuàng)建子類(代理對(duì)象)
21         return en.create();
22     }
23 
24     @Override
25     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
26         System.out.println("向觀眾問(wèn)好");
27         //執(zhí)行目標(biāo)對(duì)象的方法
28         Object returnValue = method.invoke(target, args);
29         System.out.println("謝謝大家");
30         return returnValue;
31     }
32 }

這里的代碼也非常固定,只有標(biāo)黃部分是需要自己寫出

測(cè)試

 1 /**
 2  * 測(cè)試類
 3  */
 4 public class Test{
 5     public static void main(String[] args){
 6         //目標(biāo)對(duì)象
 7         Singer target = new Singer();
 8         //代理對(duì)象
 9         Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
10         //執(zhí)行代理對(duì)象的方法
11         proxy.sing();
12     }
13 }

總結(jié):三種代理模式各有優(yōu)缺點(diǎn)和相應(yīng)的適用范圍,主要看目標(biāo)對(duì)象是否實(shí)現(xiàn)了接口。以Spring框架所選擇的代理模式舉例

  • 在Spring的AOP編程中:
  • 如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,用JDK代理
  • 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,用Cglib代理

到此這篇關(guān)于Java的三種代理模式簡(jiǎn)述的文章就介紹到這了,更多相關(guān)Java的三種代理模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論