詳解JAVA設(shè)計(jì)模式之代理模式
什么是設(shè)計(jì)模式(Design Pattern)?
設(shè)計(jì)模式是一套被反復(fù)使用,多數(shù)人知曉的,經(jīng)過(guò)分類編目的,代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
代理模式的定義?
代理模式就是為其他對(duì)象提供一種代理,以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。
代理對(duì)象起到中介作用,可去掉功能服務(wù)或增加額外的服務(wù)。
代理對(duì)象和目標(biāo)對(duì)象的關(guān)系?
代理對(duì)象:增強(qiáng)后的對(duì)象
目標(biāo)對(duì)象:被增強(qiáng)的對(duì)象
他們不是絕對(duì)的,會(huì)根據(jù)情況發(fā)生變化。
代理模式的兩種實(shí)現(xiàn)方式?
1.靜態(tài)代理:代理和被代理對(duì)象在代理之前是確定的,它們都實(shí)現(xiàn)相同的接口或者繼承相同的抽象類。
2.動(dòng)態(tài)代理:JDK通過(guò)接口反射得到字節(jié)碼,然后把字節(jié)碼轉(zhuǎn)換成class(通過(guò)native方法)
靜態(tài)代理實(shí)現(xiàn)的兩種方式?
使用繼承方式實(shí)現(xiàn)和使用聚合方式實(shí)現(xiàn)。
繼承:代理對(duì)象繼承目標(biāo)對(duì)象,重寫需要增強(qiáng)的方法。缺點(diǎn):代理類過(guò)多,產(chǎn)生類爆炸。
聚合:目標(biāo)對(duì)象和代理對(duì)象實(shí)現(xiàn)同一個(gè)接口,代理對(duì)象當(dāng)中要包含目標(biāo)對(duì)象。
動(dòng)態(tài)代理的實(shí)現(xiàn)方式?
Java動(dòng)態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個(gè)類:
1.Interface InvocationHandler : 該接口中僅定義了一個(gè)方法,public Object invoke(Object obj,Method method,Object[] args),在實(shí)際使用時(shí),第一個(gè)參數(shù)obj一般是指代理類,method是被代理的方法,args是該方法的參數(shù)數(shù)組,這個(gè)抽象方法在代理類中動(dòng)態(tài)實(shí)現(xiàn)。
2.Proxy 該類即為動(dòng)態(tài)代理類,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個(gè)實(shí)例,返回后的代理類可以當(dāng)做被代理類使用(可使用被代理類在接口中聲明過(guò)的方法)
所謂的動(dòng)態(tài)代理是這樣一種class:它是在運(yùn)行時(shí)生成的class,該class需要實(shí)現(xiàn)一組interface,使用動(dòng)態(tài)代理類時(shí),必須實(shí)現(xiàn)InvocationHandler接口。
JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理的區(qū)別?
1.JDK動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的類,沒(méi)有實(shí)現(xiàn)接口的類不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理。
2.CGLIB動(dòng)態(tài)代理針對(duì)類來(lái)實(shí)現(xiàn)代理的,對(duì)指定目標(biāo)類產(chǎn)生一個(gè)子類,通過(guò)方法攔截技術(shù)攔截所有的父類方法的調(diào)用。
動(dòng)態(tài)代理實(shí)現(xiàn)的思路:
1.聲明一段源碼(動(dòng)態(tài)產(chǎn)生代理)
2.編譯源碼(JDK Compiler API ),產(chǎn)生新的類(代理類)
3.將這個(gè)類load到內(nèi)存中,產(chǎn)生一個(gè)新的對(duì)象(代理對(duì)象)
4.return 代理對(duì)象。
使用靜態(tài)代理的例子:
1.首先創(chuàng)建業(yè)務(wù)邏輯接口
/**
* 接口
* @author Administrator
*
*/
public interface Moveable {
/**
*
* 接口中的方法
* @Description: TODO
* @returnType: void
*/
void move();
}
2.創(chuàng)建實(shí)現(xiàn)類,實(shí)現(xiàn)接口中的方法
/**
* 實(shí)現(xiàn)類
* @author Administrator
*
*/
public class Car implements Moveable {
@Override
public void move() {
//實(shí)現(xiàn)開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.使用繼承方式實(shí)現(xiàn)對(duì)實(shí)現(xiàn)類的代理
/**
* 使用繼承方式實(shí)現(xiàn)代理
* @author Administrator
*
*/
public class Car2 extends Car {
/* (non-Javadoc)
* @see com.wk.design.proxy.Car#move()
* 直接調(diào)用父類的move方法,這樣就形成了一個(gè)Car2對(duì)Car的代理
*/
@Override
public void move() {
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛...");
//使用繼承的方式調(diào)用父類的move()方法
super.move();
long endTime = System.currentTimeMillis();
System.out.println("汽車行駛結(jié)束... 汽車行駛時(shí)間:"+(endTime-startTime)+"毫秒。");
}
}
4.創(chuàng)建測(cè)試類
/**
* 測(cè)試類
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
// Car car = new Car();
// car.move();
//使用繼承方式實(shí)現(xiàn)代理
Moveable car2 = new Car2();
car2.move();
//使用聚合方式實(shí)現(xiàn)代理
// Car car = new Car();
// Moveable car3 = new Car3(car);
// car3.move();
}
}
5.使用聚合方式實(shí)現(xiàn)對(duì)實(shí)現(xiàn)類的代理
日志代理類
/**
*
* 日志代理類
* @author Administrator
*
*/
public class CarLogProxy implements Moveable {
/**
* 使用接口聲明代理類
*/
private Moveable m;
/**
* 通過(guò)構(gòu)造方法的參數(shù)傳入代理類
* @param m
*/
public CarLogProxy(Moveable m) {
super();
this.m = m;
}
@Override
public void move() {
System.out.println("日志開始");
//調(diào)用代理類的方法
m.move();
System.out.println("日志結(jié)束");
}
}
時(shí)間代理類
/**
* 時(shí)間代理類
* @author Administrator
*
*/
public class CarTimeProxy implements Moveable {
/**
* 使用接口聲明代理類
*/
private Moveable m;
/**
* 通過(guò)構(gòu)造方法的參數(shù)傳入代理類
* @param m
*/
public CarTimeProxy(Moveable m) {
super();
this.m = m;
}
@Override
public void move() {
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛...");
//調(diào)用代理類的方法
m.move();
long endTime = System.currentTimeMillis();
System.out.println("汽車行駛結(jié)束... 汽車行駛時(shí)間:"+(endTime-startTime)+"毫秒。");
}
}
6.創(chuàng)建聚合方式測(cè)試類
/**
* 聚合代理測(cè)試類
* @author Administrator
*
*/
public class TestJuHeProxy {
public static void main(String[] args) {
Car car = new Car();
//先記錄日志,再記錄時(shí)間
// CarTimeProxy ctp = new CarTimeProxy(car);
// CarLogProxy clp = new CarLogProxy(ctp);
// clp.move();
//先記錄時(shí)間,再記錄日志
CarLogProxy clp = new CarLogProxy(car);
CarTimeProxy ctp = new CarTimeProxy(clp);
ctp.move();
}
}
使用JDK動(dòng)態(tài)代理實(shí)現(xiàn)的例子:
1.創(chuàng)建一個(gè)實(shí)現(xiàn)接口InvocationHandler的類,它必須實(shí)現(xiàn)invoke()方法。
2.創(chuàng)建被代理類及接口
3.調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個(gè)代理類
4.通過(guò)代理調(diào)用方法
/**
* 使用jdk的動(dòng)態(tài)代理
* @author Administrator
*
*/
public class TimeHandler implements InvocationHandler {
/**
* 被代理對(duì)象
*/
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* 參數(shù):
* proxy : 被代理對(duì)象
* method : 被代理對(duì)象的方法
* args : 方法的參數(shù)
* 返回值:
* Object 方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在執(zhí)行被代理對(duì)象的方法之前執(zhí)行自己的邏輯
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛...");
//執(zhí)行被代理對(duì)象的方法
method.invoke(target);
//在執(zhí)行被代理對(duì)象的方法之后執(zhí)行自己的邏輯
long endTime = System.currentTimeMillis();
System.out.println("汽車行駛結(jié)束... 汽車行駛時(shí)間:"+(endTime-startTime)+"毫秒。");
return null;
}
}
/**
* JDK動(dòng)態(tài)代理測(cè)試類
* @author Administrator
*
*/
public class JdkProxyTest {
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/**
* 參數(shù):
* loader : 類加載器
* interfaces : 實(shí)現(xiàn)接口
* h InvocationHandler
*/
Moveable m= (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
//執(zhí)行被代理類的方法
m.move();
}
}
使用CGLIB動(dòng)態(tài)代理實(shí)現(xiàn)的例子:
1.創(chuàng)建代理類,實(shí)現(xiàn)MethodInterceptor接口
2.使用Enhancer類創(chuàng)建代理方法
3.創(chuàng)建被代理類,并編寫代理方法
4.通過(guò)代理調(diào)用方法
/**
* 使用cglib動(dòng)態(tài)代理
* @author Administrator
*
*/
public class Train {
public void move(){
System.out.println("火車行駛中。。。");
}
}
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
//創(chuàng)建代理類方法
public Object getProxy(Class clazz){
//設(shè)置創(chuàng)建子類的類
enhancer.setSuperclass(clazz);
//回調(diào)函數(shù)
enhancer.setCallback(this);
//創(chuàng)建并返回子類的實(shí)例
return enhancer.create();
}
/**
* 作用:攔截所有目標(biāo)類方法的調(diào)用
* obj : 目標(biāo)類的實(shí)例
* m : 目標(biāo)方法的反射對(duì)象
* args : 方法的參數(shù)
* proxy : 代理類的實(shí)例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {
//在調(diào)用方法時(shí)實(shí)現(xiàn)自己的業(yè)務(wù)邏輯
System.out.println("日志開始...");
//代理類調(diào)用父類的方法
proxy.invokeSuper(obj, args);
//調(diào)用方法之后實(shí)現(xiàn)自己的業(yè)務(wù)邏輯
System.out.println("日志結(jié)束...");
return null;
}
}
/**
* 使用cglib動(dòng)態(tài)代理的測(cè)試類
* @author Administrator
*
*/
public class CglibProxyTest {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//傳入要代理的類
Train t = (Train)proxy.getProxy(Train.class);
//執(zhí)行方法
t.move();
}
}
以上就是詳解JAVA設(shè)計(jì)模式之代理模式的詳細(xì)內(nèi)容,更多關(guān)于JAVA 代理模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot中redis的緩存穿透問(wèn)題實(shí)現(xiàn)
這篇文章主要介紹了springboot中redis的緩存穿透問(wèn)題實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Spring Boot jar 啟動(dòng)時(shí)設(shè)置環(huán)境參數(shù)的操作
這篇文章主要介紹了Spring Boot jar 啟動(dòng)時(shí)設(shè)置環(huán)境參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
SpringBoot?如何將項(xiàng)目打包成?jar?包
這篇文章主要介紹了SpringBoot如何將項(xiàng)目打包成jar包,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
java LRU(Least Recently Used )詳解及實(shí)例代碼
這篇文章主要介紹了java LRU(Least Recently Used )詳解及實(shí)例代碼的相關(guān)資料,Java里面實(shí)現(xiàn)LRU緩存通常有兩種選擇,一種是使用LinkedHashMap,一種是自己設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu),使用鏈表+HashMap,需要的朋友可以參考下2016-11-11

