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

