淺析Java中靜態(tài)代理和動態(tài)代理的應(yīng)用與區(qū)別
一、靜態(tài)代理
1、靜態(tài)代理引入
代理模式在我們生活中很常見,比如我們購物,可以從生產(chǎn)工廠直接進行購物,但是在生活中往往不是這樣,一般都是廠家委托給超市進行銷售,而我們不直接跟廠家進行關(guān)聯(lián),這其中就引用了靜態(tài)代理的思想,廠家相當于真實角色,超市相當于代理角色,我們則是目標角色。代理角色的作用其實就是,幫助真實角色完成一些事情,在真實角色業(yè)務(wù)的前提下,還可以增加其他的業(yè)務(wù)。AOP切面編程就是運用到了這一思想。
2、靜態(tài)代理案例
寫一個小小的案例,通過婚慶公司,來實現(xiàn)靜態(tài)代理
/** * @ClassName StaticProxy * @Description TODO 靜態(tài)代理(模擬婚慶公司實現(xiàn)) * @Author ZhangHao * @Date 2022/12/11 11:38 * @Version: 1.0 */ public class StaticProxy { public static void main(String[] args) { Marry marry = new WeddingCompany(new You()); marry.happyMarry(); //注意:真實對象和代理對象要實現(xiàn)同一個接口 } } //結(jié)婚 interface Marry{ //定義一個結(jié)婚的接口 void happyMarry(); } //你(真實角色) class You implements Marry{ @Override public void happyMarry() { System.out.println("張三結(jié)婚了!"); } } //婚慶公司(代理角色) class WeddingCompany implements Marry{ //引入真實角色 private Marry target; public WeddingCompany(Marry target){ this.target = target; } @Override public void happyMarry() { //在結(jié)婚前后增加業(yè)務(wù) before(); target.happyMarry(); after(); } private void before(){ System.out.println("結(jié)婚之前:布置婚禮現(xiàn)場"); } private void after(){ System.out.println("結(jié)婚之后:收尾工作"); } }
對于Java中的Thread底層就使用的靜態(tài)代理模式,源碼分析
//Thread類實現(xiàn)了Runnable接口 public class Thread implements Runnable{ //引入了真實對象 private Runnable target; //代理對象中的構(gòu)造器 public Thread(Runnable target, String name) { init(null, target, name, 0); } }
當我們開啟一個線程,其實就是定義了一個真實角色實現(xiàn)了Runnable接口,重寫了run方法。
public void TestRunnable{ public static void main(String[] args){ MyThread myThread = new MyThread(); new Thread(myThread,"張三").start(); //Thread就是代理角色,myThread就是真實角色,start()就是實現(xiàn)方法 } } class MyThread implements Runnable{ @Override public void run() { System.out.println("我是子線程,同時是真實角色"); } }
二、動態(tài)代理
1、動態(tài)代理的引入
上面使用到了靜態(tài)代理,代理類是自己手工實現(xiàn)的,自己創(chuàng)建了java類表示代理類,同時要代理的目標類也是確定的,如果當目標類增多時,代理類也需要成倍的增加,代理類的數(shù)量過多,當接口中的方法改變或者修改時,會影響實現(xiàn)類,廠家類,代理都需要修改,于是乎就有了jdk動態(tài)代理。
2、動態(tài)代理的好處
- 代理類數(shù)量減少
- 修改接口中的方法不影響代理類
- 實現(xiàn)解耦合,讓業(yè)務(wù)功能和日志、事務(wù)和非事務(wù)功能分離
3、動態(tài)代理的實現(xiàn)步驟
- 創(chuàng)建接口,定義目標類要完成功能。
- 創(chuàng)建目標類實現(xiàn)接口。
- 創(chuàng)建InvocationHandler接口實現(xiàn)類,在invoke()方法中完成代理類的功能。
- 使用Proxy類的靜態(tài)方法,創(chuàng)建代理對象,并且將返回值轉(zhuǎn)換為接口類型。
以下是代碼案例:
/** * @ClassName DynamicProxy * @Description TODO 動態(tài)代理 * @Author ZhangHao * @Date 2022/12/11 15:11 * @Version: 1.0 */ public class DynamicProxy { public static void main(String[] args) { //創(chuàng)建目標對象 Marry target = new You(); //創(chuàng)建InvocationHandler對象 MyInvocationHandler handler = new MyInvocationHandler(target); //創(chuàng)建代理對象 Marry proxy = (Marry)handler.getProxy(); //通過代理執(zhí)行方法,會調(diào)用handle中的invoke()方法 proxy.happyMarry(); } } //創(chuàng)建結(jié)婚接口 interface Marry{ void happyMarry(); } //目標類實現(xiàn)結(jié)婚接口 class You implements Marry{ @Override public void happyMarry() { System.out.println("張三結(jié)婚了!"); } } //創(chuàng)建工具類,即方法增強的功能 class ServiceTools{ public static void before(){ System.out.println("結(jié)婚之前:布置婚禮現(xiàn)場"); } public static void after(){ System.out.println("結(jié)婚之后:清理結(jié)婚現(xiàn)場"); } } //創(chuàng)建InvocationHandler的實現(xiàn)類 class MyInvocationHandler implements InvocationHandler{ //目標對象 private Object target; public MyInvocationHandler(Object target){ this.target = target; } //通過代理對象執(zhí)行方法時,會調(diào)用invoke()方法 /** * @Param [proxy:jdk創(chuàng)建的代理類的實例] * @Param [method:目標類中被代理方法] * @Param [args:目標類中方法的參數(shù)] * @return java.lang.Object **/ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //增強功能 ServiceTools.before(); //執(zhí)行目標類中的方法 Object obj = null; obj = method.invoke(target,args); ServiceTools.after(); return obj; } //通過Proxy類創(chuàng)建代理對象(自己手寫的嗷) /** * @Param [ClassLoader loader:類加載器,負責向內(nèi)存中加載對象的,使用反射獲取對象的ClassLoader] * @Param [Class<?>[] interfaces: 接口, 目標對象實現(xiàn)的接口,也是反射獲取的。] * @Param [InvocationHandler h: 我們自己寫的,代理類要完成的功能。] * @return java.lang.Object **/ public Object getProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } }
三、總結(jié)
代理分為靜態(tài)代理和動態(tài)代理
靜態(tài)代理需要手動書寫代理類,動態(tài)代理通過Proxy.newInstance()方法生成
不管是靜態(tài)代理還是動態(tài)代理,代理與被代理者都要實現(xiàn)兩樣接口,本質(zhì)面向接口編程
代理模式本質(zhì)上的目的是為了在不改變原有代碼的基礎(chǔ)上增強現(xiàn)有代碼的功能
到此這篇關(guān)于淺析Java中靜態(tài)代理和動態(tài)代理的應(yīng)用與區(qū)別的文章就介紹到這了,更多相關(guān)Java靜態(tài)代理和動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springAop實現(xiàn)權(quán)限管理數(shù)據(jù)校驗操作日志的場景分析
這篇文章主要介紹了springAop實現(xiàn)權(quán)限管理數(shù)據(jù)校驗操作日志的場景分析,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Java執(zhí)行cmd命令兩種實現(xiàn)方法解析
這篇文章主要介紹了Java執(zhí)行cmd命令兩種實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07SSH框架網(wǎng)上商城項目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示
SSH框架網(wǎng)上商城項目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示,提供了豐富的選擇、排序、分組和編輯數(shù)據(jù)的功能支持,感興趣的小伙伴們可以參考一下2016-05-05Mybatis-plus自定義SQL注入器查詢@TableLogic邏輯刪除后的數(shù)據(jù)詳解
這篇文章主要給大家介紹了關(guān)于Mybatis-plus自定義SQL注入器查詢@TableLogic邏輯刪除后的數(shù)據(jù)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-03-03Java replaceAll()方法報錯Illegal group reference的解決辦法
這篇文章主要給大家介紹了關(guān)于Java replaceAll()方法報錯Illegal group reference的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09