本節要點:
Java靜態代理
Jdk動態代理
1 面向對象設計思想遇到的問題
在傳統OOP編程里以對象為核心,並通過對象之間的協作來形成一個完整的軟件功能,由於對象可以繼承,因此我們可以把具有相同功能或相同特徵的屬性抽像到一個層次分明的類結構體系中。隨著軟件規範的不斷擴大,專業化分工越來越系列,以及OOP應用實踐的不斷增多,隨之也暴露了一些OOP無法很好解決的問題。
現在假設系統中有三段完全相似的代碼,這些代碼通常會採用“複製”、“粘貼”方式來完成,通過這種方式開發出來的軟件如圖所示:
可能讀者已經發現了這種做法的不足之處,如果有一天,藍色背景的代碼需要修改,那是不是要同時修改三個地方?如果不僅僅是這三個地方包含這段代碼,而是100個,甚至是1000個地方,那會是什麼後果?
記錄日誌在代碼中無處不在---先來看一個例子:
為了跟踪應用程序的運行過程,很多方法都需要記錄日誌信息。我們一般這樣寫:
//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)定義接口:
public interface IPerson {public abstract void sleep();public abstract void eating();}2) 被代理類
public class Person implements IPerson {public void sleep(){System.out.println("睡覺中");}public void eating(){System.out.println("正在吃飯中");}}3) 代理類
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) 測試類
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)
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) 生產代理對象的工廠
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) 測試類
public class PersonTest {public static void main(String[] args) {IPerson person = (IPerson) DynaProxyFactory.getProxy(new Person());//返回代理類,代理類是JVM在內存中動態創建的,該類實現傳入的接口數組的全部接口(的全部方法).person.eating();person.sleep();}}總結
以上就是本文關於Spring靜態代理和動態代理代碼詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站:
Spring常用配置及解析類說明
SpringMVC攔截器實現單點登錄
Java編程實現springMVC簡單登錄實例
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!