java代理的原理及應用

什么是代理模式?

  定義

    為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

                                                                  ——百度百科

  代理模式的角色

  抽象角色:代理對象和真實對象的共同接口

  代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能夠代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。

  真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。

  示意圖

    

代理模式的分類及使用

  • 靜態代理

1 package staticProxy;
2 
3 // 抽象角色,真是對象與代理對象的共同接口
4 public interface Subject {
5     public void request();
6 }
抽象角色
 1 package staticProxy;
 2 
 3 //代理對象,用來被客戶端直接調用的類,內部被注入真實對象,可以在調用真是對象的方法前后做預處理和后處理
 4 public class ProxyClass implements Subject {
 5     
 6     Subject subject;
 7     
 8     ProxyClass (Subject subject) {
 9         this.subject = subject;
10     }
11 
12     @Override
13     public void request() {
14         System.out.println("prefix-process!");
15         subject.request();
16         System.out.println("suffix-process!");
17     }
18 
19 }
代理角色
 1 package staticProxy;
 2 
 3 //真實對象,委托類
 4 public class RealClass implements Subject {
 5 
 6     @Override
 7     public void request() {
 8         System.out.println("I'm realClass!");
 9     }
10 
11 }
真實角色
 1 package staticProxy;
 2 
 3 //客戶端
 4 public class StaticProxy {
 5     public static void main(String[] args) {
 6         Subject subject = new ProxyClass(new RealClass());
 7         
 8         subject.request();
 9     }
10 }
客戶端

    靜態代理的缺點很顯著,對每一個委托類都需要創建一個代理類,為了解決這個問題,java提供了動態代理。

  • 動態代理

    抽象角色與真實角色的定義和靜態代理完全一致,這里不再重復定義

    動態代理類需要繼承自InvocationHandler接口,并實現其中的invoke方法。

 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class ProxyClass implements InvocationHandler {
 7 
 8     Object subject;
 9     
10     public ProxyClass(Object subject) {
11         this.subject = subject;
12     }
13     
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
16         System.out.println("prefix-process!");
17         method.invoke(subject, args);
18         System.out.println("suffix-process!");
19         return null;
20     }
21 
22 }
動態代理類
 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 public class DynamicProxy {
 6     public static void main(String[] args) {
 7         
 8         Subject subject = (Subject) Proxy.newProxyInstance(RealClass.class.getClassLoader(),
 9                 new Class[] {Subject.class}, new ProxyClass(new RealClass()));
10         
11         subject.request();
12     }
13 }
客戶端

動態代理的實現原理

動態代理的實現主要依賴于java.lang.reflect.InvocationHandler接口與java.lang.reflect.Proxy類,其實現原理是基于java的反射技術。

InvocationHandler接口

    動態代理類需要繼承自InvocationHandler接口,此接口中只包含一個方法invoke方法,接口原型如下:

 1 package java.lang.reflect;
 2 
 3 public interface InvocationHandler {
 4 
 5     /**
 6      * proxy:代表代理對象本身,用于調用本代理對象的其他方法
 7      * method:代表正在被調用的委托類的方法
 8      * args:代表調用方法的參數
 9      */
10     public Object invoke(Object proxy, Method method, Object[] args)
11         throws Throwable;
12 }
InvocationHandler

Proxy類

    Proxy類中定義了很多的方法,但根據上面動態代理的應用我們看到,最重要的一個方法就是newProxyInstance方法,該方法的作用就是動態創建一個代理類對象:

 1     /**
 2      * loader代表了委托類的類加載器
 3      * interfaces代表了委托類的接口數組
 4      * h代表委托類的實例
 5      */
 6     @CallerSensitive
 7     public static Object newProxyInstance(ClassLoader loader,
 8                                           Class<?>[] interfaces,
 9                                           InvocationHandler h)
10         throws IllegalArgumentException
11     {
12         // 判斷委托類實例是否為空,如果未空拋異常
13         Objects.requireNonNull(h);
14 
15         final Class<?>[] intfs = interfaces.clone();
16         final SecurityManager sm = System.getSecurityManager();
17         if (sm != null) {
18             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
19         }
20 
21         /*
22          * 獲取獲取代理類的Class實例
23          */
24         Class<?> cl = getProxyClass0(loader, intfs);
25 
26         /*
27          * Invoke its constructor with the designated invocation handler.
28          */
29         try {
30             if (sm != null) {
31                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
32             }
33 
34             //獲取代理類的Constructor對象
35             final Constructor<?> cons = cl.getConstructor(constructorParams);
36             final InvocationHandler ih = h;
37             if (!Modifier.isPublic(cl.getModifiers())) {
38                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
39                     public Void run() {
40                         cons.setAccessible(true);
41                         return null;
42                     }
43                 });
44             }
45 
46             //利用反射原理中使用constructor動態創建動態代理類型
47             return cons.newInstance(new Object[]{h});
48         } catch (IllegalAccessException|InstantiationException e) {
49             throw new InternalError(e.toString(), e);
50         } catch (InvocationTargetException e) {
51             Throwable t = e.getCause();
52             if (t instanceof RuntimeException) {
53                 throw (RuntimeException) t;
54             } else {
55                 throw new InternalError(t.toString(), t);
56             }
57         } catch (NoSuchMethodException e) {
58             throw new InternalError(e.toString(), e);
59         }
60     }
newProxyInstance

動態代理的應用場景

  動態代理最著名的應用場景就是spring中的aop

  

轉載于:https://www.cnblogs.com/qq455988971/p/8242946.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251162.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251162.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251162.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue --- 過濾器、計算、方法、觀察屬性

過濾器屬性:filters: <div id "app">{{num}}<br>{{num | toInt}}<br>{{num | toFloor}}<br>{{num | toCeil}}<br> </div> <script>let vm new Vue({el: #app,data:{num:3.45,},// 過濾器filters:{toInt(value){return …

《你不知道的JavaScript(上卷)》讀書筆記

第一次嘗試用思維導圖記筆記&#xff0c;感覺還不錯~~~不過還是改不了我讀書筆記寫成抄書筆記的毛病 。 因為開始學JS的時候&#xff0c;一般瀏覽器就已經支持ES6了&#xff0c;所以比較喜歡使用ES6語法&#xff0c;let&#xff0c;>等&#xff0c;文中代碼不是抄書的&#…

ES5-15 數組基礎、數組方法、數組排序

創建數組 字面量 var arr []構造函數 var arr new Array()不使用new var arr Array() 所有數組都繼承于Array.prototype&#xff0c;能使用其中的數組方法 數組是另一種形式的對象&#xff0c;訪問機制相同數組的empty項打印出來是undefined&#xff0c;empty不是值只是一個…

Centos 7 配置 NFS

安裝NFS包 yum install nfs-utils.x86_64 啟動NFS服務需要首先啟動rpcbind服務&#xff0c;這個rpcbind包已經在上面安裝好了 先配置 /etc/exports 文件 vi /etc/exports /etc/exports文件內容格式&#xff1a; <輸出目錄> [客戶端1 選項&#xff08;訪問權限,用戶映射,其…

數學期望筆記

基礎知識點 首先明確期望公式:\[E(X)∑_ip_i*x_i\] 其中 \(p\) 代表概率 , \(x\) 代表發生貢獻。 然后期望的幾點性質: 對于數學期望&#xff0c;我們還應該明確一些知識點&#xff1a; (1) 期望的“線性”性質 對于所有滿足條件的離散型的隨機變量\(X,Y\)和常量\(a,b\)有: \[E…

vue --- vue中的幾個鉤子屬性

1.創建前:beforeCreate <div id"app">{{name}}</div><script>let app new Vue({el:#app,data:{name:31231312},beforeCreate(){console.log(掛在前);console.log(this.$data);console.log(this.$el);}})</script>// beforeCreate()是在Vue掛…

ES5-16【utils】數組方法、類數組

數組方法 concat 返回值是拼接后的數組 toString 將數組轉成字符串&#xff0c;用逗號隔開 slice(a&#xff0c;b) [a&#xff0c;b) 不傳值&#xff0c;拷貝了一份不傳b&#xff0c;截取到最后一位傳b&#xff0c;截取到b之前的那位a/b是負數&#xff08;和splice一樣&a…

Catalan卡塔蘭數

卡塔蘭數 卡塔蘭數是組合數學中一個常出現在各種計數問題中出現的數列。由以比利時的數學家歐仁查理卡塔蘭 (1814–1894)命名。 卡塔蘭數的一般項公式為 另類遞歸式&#xff1a; h(n)((4*n-2)/(n1))*h(n-1); 前幾項為: 1, 1, 2, 5, 14, 42, 132, 429, …

vue --- v-html、v-bind

v-html // 有時候,我們需要展示<strong>,但直接使用下面的語法并不會顯示 <div id "app">{{name}}</div><script>let app new Vue({el:#app,data:{name:<strong>啦啦啦</strong>}}); </scritp> // 結果當然沒讓人失望此…

在樹莓派是安裝并配置NTP服務

我們都知道樹莓派的小巧和省電節省空間等太多的優勢&#xff0c;這里就不一一列舉了&#xff0c;那么樹莓派就需要長時間的運行&#xff0c;可以724的方式運行&#xff0c;那么我們就把樹莓派當作一個小的服務器來運行&#xff0c;可以跑一些小的應用&#xff0c;例如可以在局域…

Oracle使用總結

1. 在ORACLE中Service Name即為數據庫名稱&#xff1b; 2. 在做刪除操作時&#xff0c;需要加Commit進行操作提交&#xff1b; 3. 使用sqlldr將數據進行批量導入到ORACLE中&#xff1a; 3.1 Sqlldr命令的用法&#xff1a; sqlldr useridLoginName/PasswordTNSName controlC:\U…

ES5-17/18 錯誤信息、try_catch、嚴格模式

錯誤信息 語法錯誤 標識符名稱&#xff08;變量、函數名&#xff09;不規范對關鍵字賦值基本語法錯誤&#xff0c;如分號打錯 引用錯誤 變量、函數未聲明給無法賦值的對象賦值var a 1 2 范圍錯誤 數組長度為負數方法參數超出可行范圍toFixed(-1) 類型錯誤 調用不存在…

vue --- v-text、v-show、v-if、v-else

v-text: <div id "app"><p v-text"msg"></p> </div> <script>let app new Vue({el:#app,data:{msg:Hello Vue}}) </script>// 可見v-text在某種程度上等價于 {{}}v-show: <div id "app"><div…

查找mac下騰訊視頻下載地址

mac 騰訊視頻下載的視頻是不可見的&#xff0c;也許是因為版權原因吧。使用以下方法可以在文件中找到緩存的視頻&#xff08;不過都是被斷開的很多短視頻&#xff09;。 在terminal輸入&#xff1a; cd Library/Containers/ 然后ls查看。查看當前的所有文件夾&#xff0c;你會看…

JS 新建web sql 數據表

//新建web sql數據庫數據表var tbName"tableName";var strSQL"create table if not exists tableName (id unique,th1,th2,th3)";function creatBDTable(strSQL,tbName){db openDB();db.transaction(function(tr) {tr.executeSql(strSQL,[],//SQL語句出成…

vue --- v-for、v-on、v-model、v-once

v-for: <div id "app"><ul><li v-for"item in list">{{item}}</li></ul> </div> <script>let app new Vue({el:#app,data:{list:[B,A,T]}}) </script>拿到索引index: <div id"app">&…

ES5-19 變量聲命周期、垃圾回收原理、arguments

變量聲命周期 垃圾回收 找出不再使用的變量釋放其占用內存固定的時間間隔運行 解除由于閉包產生的對fn AO的引用 標記清除 排除全局變量、排除閉包引用的AO中的變量進入環境 → 離開環境常用 引用計數 引用計數為0時清除對循環引用的情況&#xff0c;如果不手動接觸引用…

bzoj 1801: [Ahoi2009]chess 中國象棋【dp】

注意到一行只能放012個炮&#xff0c;我們只需要知道列的狀態&#xff0c;不用狀壓行 所以設f[i][j][k]表示前i行有j列有1個炮&#xff0c;有k列有2個炮的方案數 然后分情況討論轉移就行了 #include<cstdio> #include<iostream> using namespace std; const int N1…

vue --- compoent妙用

首先利用寫一個靜態模板的組件 <div id "app"><my-arti></my-arti> </div> <script>Vue.component(my-arti,{template:<div style"border:1px solid black"><span>date:2019年06月14日</span><br>…

ES5-20 復習

3-1 變量單一聲明方式String Boolean undefined Number nullundefined nulltypeof(null) ‘object’typeof(方法) ‘function’typeof() 是運算符&#xff0c;不是數據類型 報錯0 -0 trueInfinity -Infinity falseNaN和誰都不等原始值沒有屬性 要打印屬性、調用方法得經過基…