国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Java > 正文

Java動態(tài)代理(設(shè)計模式)代碼詳解

2024-07-13 10:15:27
字體:
供稿:網(wǎng)友

基礎(chǔ):需要具備面向?qū)ο笤O(shè)計思想,多態(tài)的思想,反射的思想;

Java動態(tài)代理機制的出現(xiàn),使得Java開發(fā)人員不用手工編寫代理類,只要簡單地指定一組接口及委托類對象,便能動態(tài)地獲得代理類。代理類會負責(zé)將所有的方法調(diào)用分派到委托對象上反射執(zhí)行,在分派執(zhí)行的過程中,開發(fā)人員還可以按需調(diào)整委托類對象及其功能,這是一套非常靈活有彈性的代理框架。通過閱讀本文,讀者將會對Java動態(tài)代理機制有更加深入的理解。本文首先從Java動態(tài)代理的運行機制和特點出發(fā),對其代碼進行了分析,推演了動態(tài)生成類的內(nèi)部實現(xiàn)。

代理模式的基本概念和分類

代理模式:為其他對象提供一個代理,來控制對這個對象的訪問。代理對象起到中介作用,可以去掉服務(wù)或者增加額外的服務(wù),或者引用別人的話:“代理類負責(zé)為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進行消息被委托類執(zhí)行后的后續(xù)處理。”

代理模式在開發(fā)中的應(yīng)用場景

遠程代理:為不同地理的對象提供局域網(wǎng)代表對象。

虛擬代理:根據(jù)需要將資源消耗很大的對象進行延遲,真正需要的時候進行創(chuàng)建。比如網(wǎng)頁中的先顯示文字再顯示圖片。

保護代理:控制不同用戶的訪問權(quán)限。比如:只有當客戶注冊成功之后,才可以進行增刪改查等操作。

智能引用代理:提供對目標代理額外的服務(wù)。

代理模式的實現(xiàn)方式

使用繼承和聚合實現(xiàn)動態(tài)代理,哪種更好呢!

public interface Moveable {	public void move();}public class Car implements Moveable{	@Override 	  public void move() {		try {			Thread.sleep(new Random().nextint(1000));			System.out.println("……行駛中……");		}		catch(InterruptedException e) {			// TODO Auto-generated catch block 			e.printStackTrace();		}	}}public class Car2 extends Car{	@Override 	  public void move() 	  {		//分離代碼,增加業(yè)務(wù)邏輯 		long startTime=System.currentTimeMillis();		System.out.println("汽車開始行駛……");		super.move();		long endTime=System.currentTimeMillis();		System.out.println("汽車結(jié)束行駛……時間:"+(endTime-startTime)+"ms");	}}

繼承方式實現(xiàn)代理

Moveablecar2=newCar2();
car2.move();

聚合方式實現(xiàn)代理

Carcar=newCar();
Moveablem=newCar3(car);
m.move();

總結(jié)

使用繼承方式不夠靈活,當功能疊加的時候,只能臃腫的擴展代理類;
使用聚合的方式,代理之間可以相互傳遞,靈活的組合代理;

public class CarLogProxy extends Car{	@Override 	  public void move() 	  {		//分離代碼,增加業(yè)務(wù)邏輯 		long startTime=System.currentTimeMillis();		System.out.println("日志開始……");		super.move();		long endTime=System.currentTimeMillis();		System.out.println("日志結(jié)束……");	}}public class CarTimeProxy implements Moveable {	public CarTimeProxy(Car car) 	  {		super();		this.car=car;	}	private Carcar;	@Override 	  public void move() {		//分離代碼,增加業(yè)務(wù)邏輯 		long startTime=System.currentTimeMillis();		System.out.println("汽車開始行駛……");		car.move();		long endTime=System.currentTimeMillis();		System.out.println("汽車結(jié)束行駛……時間:"+(endTime-startTime)+"ms");	}}@Test: Car car =new Car();CarTimeProxy ctp=new CarTimeProxy(car);CarLogProxy clp=new CarLogProxy(ctp);clp.move();//還可以通過接口相互傳遞代理實例 CarLogProxy clp1=new CarLogProxy(car);CarTimeProxy ctp1=new CarTimeProxy(clp1);ctp1.move();

JDK動態(tài)代理和CGlib動態(tài)代理

JDK動態(tài)代理

代理實現(xiàn)

如果不同的對象要實現(xiàn)相同功能的代理類,應(yīng)該如何處置?

此時可以試著將其集成在同一個代理類中-----動態(tài)代理:實現(xiàn)對不同類/不同方法的代理;

大致過程如下:

java,動態(tài)代理,設(shè)計模式

Java動態(tài)代理類位于java.lang.reflect包下,一般主要涉及到一下兩個類:

(1)InterfaceInvocationHandler:該接口中僅定義了一個方法Publicobjectinvoke(Objectobj,Methodmethod,Object[]args)

obj:一般是指代理類

method:是被代理的方法

args為該方法的參數(shù)數(shù)組。

這個抽象的方法在代理類中動態(tài)實現(xiàn)。

(2)Proxy:該類即為動態(tài)代理類

statixObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)

返回甙類類的一個實例,返回后的代理類可以當做被代理類使用(可以使用被代理類在接口中聲明過的方法);

實現(xiàn)實例:

@ TimeHandler public class TimeHandler   implements InvocationHandler {	public TimeHandler(Object target) {		super();		this.target = target;	}	private Objecttarget;	/*   * 參數(shù):   * proxy 被代理對象   * method 被代理對象的方法   * args 方法的參數(shù)   *   * 返回值:   * Object 方法返回值   */	@Override 	  public Object invoke(Object proxy, Method method,Object[] args) 	    throws Throwable {		long startTime=System.currentTimeMillis();		System.out.println("汽車開始行駛……");		method.invoke(target);		long endTime=System.currentTimeMillis();		System.out.println("汽車結(jié)束行駛……時間:"+(endTime-startTime)+"ms");		return null;	}}
@被代理類的接口public interface Moveable {  public void move();}@被代理的類
public class Car implements Moveable{	@Override 	  public void move() {		try {			Thread.sleep(new Random().nextint(1000));			System.out.println("……行駛中……");		}		catch (InterruptedException e) {			// TODO Auto-generated catch block 			e.printStackTrace();		}	}}

@測試

public class Test {   /**   * JDk動態(tài)代理的測試類   */   public static void main(String[] args) {    Car car=new Car();    InvocationHandler h=new TimeHandler(car);    Class<?>cls=car.getClass();    /*     * loader 類加載器     * interfaces 實現(xiàn)接口     * h InvocationHandler     */    Moveable m=(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);    m.move();   } } 

&&測試結(jié)果

java,動態(tài)代理,設(shè)計模式

梳理總結(jié)

所為的DynamicProxy是這樣一種class:

它是在運行時生成的class,該class需要實現(xiàn)一組interface,使用動態(tài)代理類的時候,必須實現(xiàn)InvocationHandler接口。

JDK動態(tài)代理的一般步驟

1.創(chuàng)建一個實現(xiàn)接口InvocationHandler的類,它必須實現(xiàn)invoke()

2.創(chuàng)建被代理的類以及接口

3.調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個代理類

newProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)

4.通過代理調(diào)用方法

java,動態(tài)代理,設(shè)計模式

CGlib動態(tài)代理的實現(xiàn)

代理實現(xiàn)

@引入cglib-node-2.2.jar包

@CglibProxy攔截類實現(xiàn)接口MethodInterceptor:重寫intercept攔截方法

public class CglibProxy implements MethodInterceptor {	private Enhancerenhancer=new Enhancer();	public Object getProxy(Class cl) 	  {		//設(shè)置創(chuàng)建子類的類 		enhancer.setSuperclass(cl);		enhancer.setCallback(this);		return enhancer.create();	}	/*   * 攔截所有目標類方法的調(diào)用   * object 目標類的實例   * m 目標方法的反射對象   * args 方法的參數(shù)   * proxy 代理類的實例   *   */	@Override 	  public Object intercept(Object obj, Method m,Object[] args,  MethodProxy proxy)throws Throwable 	{		System.out.println("日志開始……");		//代理類調(diào)用父類的方法 		proxy.invokeSuper(obj, args);		System.out.println("日志結(jié)束……");		return null;	}}

@被代理類Train

public class Train {   public void move()   {    System.out.println("火車行駛中……");   } } 

@測試類

public class Test {   /**   * cglibProxy動態(tài)代理測試類   */   public static void main(String[] args) {    CglibProxy proxy=new CglibProxy();    Train t=(Train)proxy.getProxy(Train.class);    t.move();   } } 

##測試結(jié)果:

java,動態(tài)代理,設(shè)計模式

梳理總結(jié)

使用CglibProxy實現(xiàn)動態(tài)代理的一般步驟

1、創(chuàng)建類實現(xiàn)接口MethodInterceptor,并重寫intercept方法

2、創(chuàng)建被代理類

3、調(diào)用代理類自定義的方法,得到一個代理實例

4、通過代理實例調(diào)用被代理類的需要執(zhí)行的方法

比較總結(jié)

JDK動態(tài)代理

1、只能代理實現(xiàn)了接口的類

2、沒有實現(xiàn)接口的類不能實現(xiàn)JDK的動態(tài)代理

CGlib動態(tài)代理

1、針對類來實現(xiàn)代理

2、對執(zhí)行目標類產(chǎn)生一個子類,通過方法攔截技術(shù)攔截所有父類方法的調(diào)用。

模擬代理產(chǎn)生步驟

思路:

實現(xiàn)功能:通過Proxy的newProxyInstance返回代理對象

1、聲明一段源碼(動態(tài)產(chǎn)生代理)

2、編譯源碼(JDKCompilerAPI)產(chǎn)生新的類(代理類)

3、將這個類load到內(nèi)存當中,產(chǎn)生一個新的對象(代理對象)

4、返回代理對象

完善動態(tài)代理實現(xiàn)

首先得到系統(tǒng)編譯器,通過編譯器得到文件管理者,然后獲取文件,然后編譯器執(zhí)行編譯任務(wù),完成編譯之后,將class文件加載到類加載器中,通過構(gòu)造方法得到實例,然后調(diào)用newInstance()接收一個對象的實例。

(1)拿到編譯器JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();

(2)文件管理者StandardJavaFileManagerfileMgr=Compiler.getStandardFileManager(null,null,null);

(3)獲取文件Iterableunits=fileMgr.getJavaFileObjects(filename);

(4)編譯任務(wù)CompilationTaskt=compiler.getTask(null,fileMgr,null,null,null,units);

(5)load到內(nèi)存

ClassLoadercl=ClassLoader.getSystemClassLoader();

Classc=cl.loadClass(”com.imooc.proxy.$Proxy0”);

(6)通過代理對象的構(gòu)造器構(gòu)造實例

Constructorctr=c.getConstructor(infce);

ctr.newInstance(newCar());

-------

上說所說,內(nèi)部的業(yè)務(wù)邏輯是硬編碼的,如何實現(xiàn)真正的動態(tài)代理,動態(tài)的指定業(yè)務(wù)邏輯呢?

1、需要創(chuàng)建一個事務(wù)處理器,首先創(chuàng)建一個接口也就是InvocationHandler,為了模擬JDK,這里把接口的名字和JDK事務(wù)處理器名稱一樣,同樣寫一個方法叫做invoke(),用來表示對某個對象的某個方法進行業(yè)務(wù)處理,所以需要把某個對象以及對象的方法作為invoke()方法的參數(shù)傳遞進來,invoke(Objectobj,Methodmethod),方法作為參數(shù)使用到了java反射,需要把此包引入。這樣InvocationHandler接口就完成了。

2、創(chuàng)建事務(wù)處理實現(xiàn)類比如說時間代理TimerProxy,實現(xiàn)了InvocationHandler接口,這樣結(jié)構(gòu)就成了

——————TimerProxyimplementsInvocationHandler{ ————————-@override ————————-voidinvoke(Objectobj,Methodmethod){ ———————————//業(yè)務(wù)邏輯<br> —————————————method.invoke(目標對象,參數(shù)); ————————————//業(yè)務(wù)邏輯<br> ——————————} —————————}

需要將目標對象傳入,沒有參數(shù)可以不寫參數(shù),創(chuàng)建代理對象的構(gòu)造方法,初始化目標對象

3、在Proxy類的newProxyInstance()方法中,除了要把目標Class接口作為參數(shù)外,還需要把事務(wù)處理器InvocationHandler傳進去,然后更改創(chuàng)建實例對象中硬編碼的部分用事務(wù)處理器方法替代即可。難點在于字符串的拼接。

總結(jié)

在我們項目中代理模式有自己的實際意義,比如說我們想要調(diào)用某個jar包下的某個類,可以在調(diào)用這個類之前之后添加一些特殊的業(yè)務(wù)邏輯,這種方式也叫作AOP面向切面編程。(在不改變原有功能的基礎(chǔ)上,添加額外的功能。)

以上就是本文關(guān)于Java動態(tài)代理(設(shè)計模式)代碼詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!


注:相關(guān)教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 定远县| 饶平县| 平谷区| 苏尼特左旗| 陵水| 乐亭县| 合作市| 教育| 九寨沟县| 瑞金市| 万宁市| 望谟县| 楚雄市| 石河子市| 宁夏| 柳河县| 肥乡县| 武定县| 读书| 抚州市| 鄂伦春自治旗| 峡江县| 鄯善县| 秭归县| 房产| 抚远县| 来凤县| 清流县| 永仁县| 潞西市| 平南县| 湄潭县| 怀化市| 信宜市| 湛江市| 谢通门县| 望城县| 广水市| 麻栗坡县| 临泽县| 禄丰县|