【版權(quán)聲明】未經(jīng)博主同意,謝絕轉(zhuǎn)載?。ㄕ?qǐng)尊重原創(chuàng),博主保留追究權(quán))
https://www.cnblogs.com/cnb-yuchen/p/18002823
出自【進(jìn)步*于辰的博客】
參考筆記一,P83;筆記二,P75.4。
- 1、概述
-
2、靜態(tài)代理的兩種形式
- 2.1 面向接口
- 2.2 面向繼承
-
3、動(dòng)態(tài)代理的兩種形式
- 3.1 JDK動(dòng)態(tài)代理
- 3.2 Cglib動(dòng)態(tài)代理
- 最后
1、概述
什么是代理模式?“代理模式”指通過為目標(biāo)對(duì)象(原代碼)創(chuàng)建代理對(duì)象,將附加功能(附加代碼)注入目標(biāo)對(duì)象的方法,從而實(shí)現(xiàn)附加功能的設(shè)計(jì)模式,分為靜態(tài)代理和動(dòng)態(tài)代理。
什么是靜態(tài)代理?“靜態(tài)代理”指為目標(biāo)類手動(dòng)創(chuàng)建代理類的代理方式。
什么是動(dòng)態(tài)代理?“動(dòng)態(tài)代理”指在不變動(dòng)原代碼的情況下,通過反射動(dòng)態(tài)創(chuàng)建代理對(duì)象的代理方式。(注:“反射”是動(dòng)態(tài)代理的底層,不可見)
2、靜態(tài)代理的兩種形式
2.1 面向接口
特點(diǎn):目標(biāo)對(duì)象與代理對(duì)象隸屬于同一接口。
看下述代碼:
1、公共接口:目標(biāo)類和代理類的公共接口。
interface IService {
int transfer(int money);
}
2、目標(biāo)類。
class Target implements IService {
@Override
public int transfer(int money) {
System.out.println("轉(zhuǎn)賬金額:" + money);
return 1;
}
}
3、代理類。
class Proxy implements IService {
private Target target;
public Proxy(Target target) {
this.target = target;
}
@Override
public int transfer(int score) {
System.out.println("打開事務(wù)");// 附加功能
int x = target.transfer(score);
System.out.println("關(guān)閉事務(wù)");
return x;
}
}
測(cè)試。
class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Target());// 創(chuàng)建代理對(duì)象
int x = proxy.transfer(10);
if (x > 0)
System.out.println("轉(zhuǎn)賬成功");
else
System.out.println("轉(zhuǎn)賬失敗");
}
}
測(cè)試結(jié)果:
2.2 面向繼承
特點(diǎn):目標(biāo)對(duì)象與代理對(duì)象是繼承關(guān)系,代理對(duì)象繼承于目標(biāo)對(duì)象。
看下述代碼:
1、目標(biāo)類。
class Target {
public int transfer(int money) {
System.out.println("轉(zhuǎn)賬金額:" + money);
return 1;
}
}
3、代理類。
class Proxy extends Target {
@Override
public int transfer(int money) {
System.out.println("打開事務(wù)");// 附加功能
int x = super.transfer(money);
System.out.println("關(guān)閉事務(wù)");
return x;
}
}
測(cè)試。
class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy();// 創(chuàng)建代理對(duì)象
int x = proxy.transfer(20);
if (x > 0)
System.out.println("轉(zhuǎn)賬成功");
else
System.out.println("轉(zhuǎn)賬失敗");
}
}
測(cè)試結(jié)果:
3、動(dòng)態(tài)代理的兩種形式
PS:靜態(tài)代理需要手動(dòng)創(chuàng)建代理類,進(jìn)而創(chuàng)建代理對(duì)象,很冗余。換個(gè)思路,反射可以根據(jù) Class 信息創(chuàng)建實(shí)例,故可以通過反射為目標(biāo)對(duì)象創(chuàng)建代理對(duì)象,則無需創(chuàng)建代理類,這就是“動(dòng)態(tài)代理”。
3.1 JDK動(dòng)態(tài)代理
特點(diǎn):面向接口,隸屬于Java API。
看下述代碼:
1、公共接口。
/**
* 目標(biāo)對(duì)象與代理對(duì)象的公共接口
* 注:因?yàn)镴DK動(dòng)態(tài)代理面向接口,故目標(biāo)對(duì)象和代理對(duì)象實(shí)現(xiàn)于同一接口
*/
interface IService {
int transfer(int money);
}
2、目標(biāo)類。
class Target implements IService {
@Override
public int transfer(int money) {
System.out.println("轉(zhuǎn)賬金額:" + money);
return 1;
}
}
測(cè)試。
class Test {
public static void main(String[] args) {
Target target = new Target();
/**
* 通過 newProxyInstance() 創(chuàng)建代理對(duì)象
* 第一個(gè)參數(shù)是目標(biāo)對(duì)象的類加載器,指定為哪個(gè)目標(biāo)對(duì)象創(chuàng)建代理對(duì)象;
* 第二個(gè)參數(shù)是目標(biāo)對(duì)象實(shí)現(xiàn)的接口,指定目標(biāo)對(duì)象和代理對(duì)象的公共接口;
* 第三個(gè)參數(shù)是攔截器對(duì)象,指定用哪個(gè)攔截器來創(chuàng)建代理對(duì)象,需要實(shí)現(xiàn) InvocationHandler 接口。
*/
// 由于代理對(duì)象 proxy 是通過反射創(chuàng)建于JVM,并無類存在,故要上轉(zhuǎn)為公共接口 IService
IService proxyInstance = (IService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 代理(調(diào)用 transfer())時(shí)執(zhí)行的方法
* @param proxy 代理對(duì)象,即 proxyInstance,暫不知如何使用
* @param method 目標(biāo)對(duì)象的 Method 的 class 對(duì)象
* @param args 目標(biāo)對(duì)象的 Method 的形參數(shù)組
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打開事務(wù)");// 附加功能
// invoke() 是反射中 Method 對(duì)象執(zhí)行時(shí)調(diào)用的方法,故動(dòng)態(tài)代理是通過反射調(diào)用目標(biāo)對(duì)象被代理的方法
Object result = method.invoke(target, args);
System.out.println("關(guān)閉事務(wù)");
return result;
}
});// 創(chuàng)建代理對(duì)象
int x = proxyInstance.transfer(50);
if (x > 0)
System.out.println("轉(zhuǎn)賬成功");
else
System.out.println("轉(zhuǎn)賬失敗");
}
}
測(cè)試結(jié)果:
可以用Lambda表達(dá)式進(jìn)行簡(jiǎn)化。
3.2 Cglib動(dòng)態(tài)代理
特點(diǎn):面向繼承,隸屬于Spring API。
看下述代碼:
1、目標(biāo)類。
class Target {
public int transfer(int money) {
System.out.println("轉(zhuǎn)賬金額:" + money);
return 1;
}
}
2、代理類。
/**
* Cglib動(dòng)態(tài)代理類,需實(shí)現(xiàn)接口 MethodInterceptor
*/
class DynamicProxy implements MethodInterceptor {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object createProxy() {
Enhancer proxy = new Enhancer();// Enhancer 類是一種類生成器
proxy.setCallback(this);// 設(shè)置攔截器,指定回對(duì)象為自身(暫不理解)
proxy.setSuperclass(target.getClass());// 設(shè)置父類,指定為哪個(gè)目標(biāo)對(duì)象創(chuàng)建代理對(duì)象
return proxy.create();// 創(chuàng)建代理對(duì)象
}
/**
* 代理(調(diào)用 transfer())時(shí)執(zhí)行的方法
* @param proxy 代理對(duì)象,即 proxyInstance,暫不知如何使用
* @param method 目標(biāo)對(duì)象的 Method 的 class對(duì)象
* @param args 目標(biāo)對(duì)象的 Method 的參數(shù)數(shù)組
* @param methodProxy 代理方法,即 Target.transfer(),暫不知如何使用
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("打開事務(wù)");// 附加功能
// invoke() 是反射中 Method 對(duì)象執(zhí)行時(shí)調(diào)用的方法,故動(dòng)態(tài)代理是通過反射調(diào)用目標(biāo)對(duì)象被代理的方法
Object result = method.invoke(target, args);
System.out.println("關(guān)閉事務(wù)");
return result;
}
}
測(cè)試。
class Test {
public static void main(String[] args) {
Target target = new Target();
Target proxyInstance = (Target) new DynamicProxy(target).createProxy();
int x = proxyInstance.transfer(100);
if (x > 0)
System.out.println("轉(zhuǎn)賬成功");
else
System.out.println("轉(zhuǎn)賬失敗");
}
}
測(cè)試結(jié)果:
同樣可以用Lambda表達(dá)式進(jìn)行簡(jiǎn)化,不過代理對(duì)象的創(chuàng)建(proxy.create())需要對(duì) Enhancer 類的屬性進(jìn)行一些設(shè)置,故進(jìn)行了封裝。
注意:JDK動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理皆可攔截所有方法,包括:toString()
、hashcode()
。不能攔截由 final 修飾方法,如:getClass()
。
最后
本文中的例子是為了闡述靜態(tài)代理和動(dòng)態(tài)代理的實(shí)現(xiàn)思想、方便大家理解而簡(jiǎn)單舉出的,不一定有實(shí)用性,大家自行擴(kuò)展。文章來源:http://www.zghlxwxcb.cn/news/detail-837618.html
本文完結(jié)。文章來源地址http://www.zghlxwxcb.cn/news/detail-837618.html
到了這里,關(guān)于[Java]靜態(tài)代理、動(dòng)態(tài)代理(基于JDK1.8)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!