深入理解java動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式(JDK/Cglib)
什么是代理模式?
代理模式:在調(diào)用處不直接調(diào)用目標(biāo)類進(jìn)行操作,而是調(diào)用代理類,然后通過(guò)代理類來(lái)調(diào)用目標(biāo)類進(jìn)行操作。在代理類調(diào)用目標(biāo)類的前后可以添加一些預(yù)處理和后處理操作來(lái)完成一些不屬于目標(biāo)類的功能。
為什么要使用代理模式?
通過(guò)代理模式可以實(shí)現(xiàn)對(duì)目標(biāo)類調(diào)用的控制、在目標(biāo)類調(diào)用前/后進(jìn)行一些不屬于目標(biāo)類的操作,如:數(shù)據(jù)驗(yàn)證、預(yù)處理、后處理、異常處理等
什么是靜態(tài)代理什么是動(dòng)態(tài)代理?
- 靜態(tài)代理:代理類只能實(shí)現(xiàn)對(duì)”特定接口的實(shí)現(xiàn)類“進(jìn)行代理
- 動(dòng)態(tài)代理:代理類可以實(shí)現(xiàn)對(duì)多種類的代理
jdk代理和cglib代理區(qū)別在哪里?
- jdk動(dòng)態(tài)代理:代理所有“實(shí)現(xiàn)的有接口”的目標(biāo)類
- cglib動(dòng)態(tài)代理:代理任意一個(gè)目標(biāo)類,但對(duì)final類和方法無(wú)法代理
不同點(diǎn):jdk動(dòng)態(tài)代理的目標(biāo)類必須實(shí)現(xiàn)的有接口,因?yàn)樵谡{(diào)用Proxy.newProxyInstance()的時(shí)候需要傳入目標(biāo)類的接口類。而cglib不做此限制。
下面看代碼分析:
定義一個(gè)Person接口
package com.zpj.designMode.proxy;
//定義一個(gè)Person接口
public interface Person {
public void doWork();
}
添加一個(gè)實(shí)現(xiàn)類:MrLi
package com.zpj.designMode.proxy;
//添加一個(gè)實(shí)現(xiàn)類
public class MrLi implements Person {
@Override
public void doWork() {
System.out.println("-----doWork");
}
}
靜態(tài)代理:
添加一個(gè)靜態(tài)代理類Proxy
package com.zpj.designMode.proxy;
//靜態(tài)代理,代理必須和目標(biāo)類實(shí)現(xiàn)共同的接口
public class Proxy implements Person {
private Person person;// 被代理人
//這里的目標(biāo)類型決定了該代理類只能代理實(shí)現(xiàn)了Person接口的實(shí)例,而不能接收其他類型參數(shù),這也就是靜態(tài)代理的局限性
public Proxy(Person person) {
this.person = person;
}
@Override
public void doWork() {
System.out.println("doSomething-----start");
person.doWork();
System.out.println("doSomething-----end");
}
}
靜態(tài)代理測(cè)試程序:
package com.zpj.designMode.proxy;
public class Run {
public static void main(String[] args) {
MrLi li = new MrLi();
Proxy proxy = new Proxy(li);
//調(diào)用處直接調(diào)用代理進(jìn)行目標(biāo)方法的操作。
proxy.doWork();
}
}
JDK動(dòng)態(tài)代理:
添加一個(gè)代理JDKProxy,該代理實(shí)現(xiàn)InvocationHandler接口且覆寫invoke方法。
package com.zpj.designMode.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/***
@author Perkins Zhu
@date 2017年3月13日 上午8:41:10
*/
public class JDKProxy implements InvocationHandler {
private Object person;// 被代理人
//這里的目標(biāo)類型為Object,則可以接受任意一種參數(shù)作為被代理類,實(shí)現(xiàn)了動(dòng)態(tài)代理。但是要注意下面的newProxyInstance()中的參數(shù)
public Object getInstance(Object person) {
this.person = person;
//與cglib的區(qū)別在于這里構(gòu)建代理對(duì)象的時(shí)候需要傳入被代理對(duì)象的接口對(duì)象,第二個(gè)參數(shù)。而cglib不需要被代理對(duì)象實(shí)現(xiàn)任何接口即可
return Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("doSomething---------start");
method.invoke(person, args);
System.out.println("doSomething---------end");
return null;
}
}
JDK動(dòng)態(tài)代理測(cè)試程序
package com.zpj.designMode.proxy.jdk;
import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;
/***
* @author Perkins Zhu
* @date 2017年3月13日 上午8:51:31
*/
public class Run {
public static void main(String[] args) {
Person person = (Person) new JDKProxy().getInstance(new MrLi());
//注意這里的person不是目標(biāo)類person,而是代理類person:debug的時(shí)候顯示null,有'$'標(biāo)識(shí)符
person.doWork();
}
}
Cglib動(dòng)態(tài)代理:
添加一個(gè)CglibProxy代理,同時(shí)實(shí)現(xiàn)MethodInterceptor接口。
package com.zpj.designMode.proxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/***
* @author Perkins Zhu
* @date 2017年3月13日 上午9:02:54
*/
public class CglibProxy implements MethodInterceptor {
private Object targetObject;
// 這里的目標(biāo)類型為Object,則可以接受任意一種參數(shù)作為被代理類,實(shí)現(xiàn)了動(dòng)態(tài)代理
public Object getInstance(Object target) {
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//注意該處代理的創(chuàng)建過(guò)程
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理對(duì)象
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
System.out.println("doSomething---------start");
obj = method.invoke(targetObject, args);
System.out.println("doSomething---------end");
return obj;
}
}
Cglib動(dòng)態(tài)代理測(cè)試程序
package com.zpj.designMode.proxy.cglib;
import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;
/***
@author Perkins Zhu
@date 2017年3月13日 上午9:07:38
*/
public class Run {
public static void main(String[] args) {
Person person = (Person)new CglibProxy().getInstance(new MrLi());
person.doWork();
}
}
仔細(xì)對(duì)比Proxy、CglibProxy和JDKProxy區(qū)分靜態(tài)代理、JDK動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理的異同點(diǎn)!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springboot集成ftp實(shí)現(xiàn)文件上傳
這篇文章主要為大家詳細(xì)介紹了springboot集成ftp實(shí)現(xiàn)文件上傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
java語(yǔ)言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例
這篇文章主要介紹了java語(yǔ)言實(shí)現(xiàn)權(quán)重隨機(jī)算法完整實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
SpringBoot+Quartz+數(shù)據(jù)庫(kù)存儲(chǔ)的完美集合
這篇文章主要介紹了SpringBoot+Quartz+數(shù)據(jù)庫(kù)存儲(chǔ)的示例代碼,本文通過(guò)實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
Spring中@DependsOn注解的作用及實(shí)現(xiàn)原理解析
這篇文章主要介紹了Spring中@DependsOn注解的作用及實(shí)現(xiàn)原理解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Java?RabbitMQ消息隊(duì)列詳解常見(jiàn)問(wèn)題
消息隊(duì)列是最古老的中間件之一,從系統(tǒng)之間有通信需求開(kāi)始,就自然產(chǎn)生了消息隊(duì)列。本文告訴什么是消息隊(duì)列,為什么需要消息隊(duì)列,常見(jiàn)的消息隊(duì)列有哪些,RabbitMQ的部署和使用2022-07-07
springboot過(guò)濾器執(zhí)行兩次的解決及跨域過(guò)濾器問(wèn)題
這篇文章主要介紹了springboot過(guò)濾器執(zhí)行兩次的解決及跨域過(guò)濾器問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
詳解eclipse項(xiàng)目中的.classpath文件原理
這篇文章介紹了eclipse項(xiàng)目中的.classpath文件的原理,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12

