本節要點:
1 面向對象設計思想遇到的問題
在傳統oop編程里以對象為核心,并通過對象之間的協作來形成一個完整的軟件功能,由于對象可以繼承,因此我們可以把具有相同功能或相同特征的屬性抽象到一個層次分明的類結構體系中。隨著軟件規范的不斷擴大,專業化分工越來越系列,以及oop應用實踐的不斷增多,隨之也暴露了一些oop無法很好解決的問題。
現在假設系統中有三段完全相似的代碼,這些代碼通常會采用“復制”、“粘貼”方式來完成,通過這種方式開發出來的軟件如圖所示:
可能讀者已經發現了這種做法的不足之處,如果有一天,藍色背景的代碼需要修改,那是不是要同時修改三個地方?如果不僅僅是這三個地方包含這段代碼,而是100個,甚至是1000個地方,那會是什么后果?
記錄日志在代碼中無處不在---先來看一個例子:
為了跟蹤應用程序的運行過程,很多方法都需要記錄日志信息。我們一般這樣寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//log4j的使用見文章“log4j介紹” import org.apache.log4j.logger; public class person { private logger logger = logger.getlogger(person. class ); public void sleep(){ logger.info(“開始執行時間:“ + new date()); system.out.println( "睡覺中" ); logger.info(“執行結束時間:” + new date()); } public void eating(){ logger.info( "開始執行時間:“ + new date()" ); system.out.println( "正在吃飯中" ); logger.info( "“執行結束時間:” + new date()" ); } } |
提問:弊端在哪里?
l混淆了業務方法本身的職責
l維護工作量巨大
2解決方案1
靜態代理:
1、需要知道核心類(被代理類)是哪一個類,并且有什么方法。
2、非核心的代碼需要重復寫多次,顯得代碼的結構臃腫,形成代碼冗余。
3、非核心類(代理類)需要實現核心類(被代理類)實現的接口,也就是他們需要實現共同的接口,但是以核心類實現的接口(被代理類)為準。
l目地是將業務代碼與日志代碼完全分離,實現松散耦合.
l代理對象與被代理對象必須實現同一接口,在代理對象中實現與日志記錄的相關服務,并在需要的時候呼叫被代理對象,而被代理對象只保留業務代碼.
靜態代理的實現
1)定義接口:
1
2
3
4
|
public interface iperson { public abstract void sleep(); public abstract void eating(); } |
2) 被代理類
1
2
3
4
5
6
7
8
|
public class person implements iperson { public void sleep(){ system.out.println( "睡覺中" ); } public void eating(){ system.out.println( "正在吃飯中" ); } } |
3) 代理類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import org.apache.log4j.logger; public class personproxy implements iperson { private iperson person; private logger logger = logger.getlogger(personproxy. class ); public personproxy(iperson person) { this .person = person; } public void eating() { logger.info( "開始執行時間:“ + new date()" ); person.eating(); logger.info( "“執行結束時間:” + new date()" ); } public void sleep() { logger.info( "開始執行時間:“ + new date()" ); person.sleep(); logger.info( "“執行結束時間:” + new date()" ); } } |
4) 測試類
1
2
3
4
5
6
7
8
|
package com.aptech.aop2; public class persontest { public static void main(string[] args) { iperson proxy = new personproxy( new person()); proxy.eating(); proxy.sleep(); } } |
靜態代理的弊端:
一個代理接口只能服務于一種類型的對象.對于稍大點的項目根本無法勝任.
3 解決方案2-動態代理
invocationhandler:每一個動態代理類都必須實現invocationhandler這個接口,并且每個代理類的實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由invocationhandler這個接口的invoke方法來進行調用。
在jdk1.3之后加入了可協助開發的動態代理功能.不必為特定對象與方法編寫特定的代理對象,使用動態代理,可以使得一個處理者(handler)服務于各個對象.
一個處理者的類設計必須實現java.lang.reflect.invocationhandler接口.
通過invocationhandler接口實現的動態代理只能代理接口的實現類.
動態代理實現
1) 處理者(handler)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class dynaproxyhandler implements invocationhandler { private logger logger = logger.getlogger(dynaproxyhandler. class ); private object target; //被代理對象 public void settarget(object target) { this .target = target; } public object invoke(object proxy, method method, object[] args) throws throwable { logger.info( "執行開始時間:" + new date()); object result = method.invoke(target, args); logger.info( "執行結束時間:" + new date()); return result; //返回method執行結果 } } |
2) 生產代理對象的工廠
1
2
3
4
5
6
7
8
9
|
import java.lang.reflect.proxy; public class dynaproxyfactory { //obj為被代理對象 public static object getproxy(object obj){ dynaproxyhandler handler = new dynaproxyhandler(); handler.settarget(obj); return proxy.newproxyinstance(obj.getclass().getclassloader(), obj.getclass().getinterfaces(), handler); } } |
3) 測試類
1
2
3
4
5
6
7
8
|
public class persontest { public static void main(string[] args) { iperson person = (iperson) dynaproxyfactory.getproxy( new person()); //返回代理類,代理類是jvm在內存中動態創建的,該類實現傳入的接口數組的全部接口(的全部方法). person.eating(); person.sleep(); } } |
總結
以上就是本文關于spring靜態代理和動態代理代碼詳解的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
原文鏈接:https://www.cnblogs.com/zhouyeqin/p/7208367.html