1.定義
代理模式是指為某個(gè)對(duì)象提供一個(gè)代理對(duì)象挤忙,來起到間接訪問的一個(gè)目的腥放,屬于結(jié)構(gòu)型設(shè)計(jì)模式比藻,在某種情況下郑象,一個(gè)對(duì)象不適合或者不能直接引用目標(biāo)對(duì)象贡这,代理對(duì)象在客戶端和目標(biāo)對(duì)象中間起到了一個(gè)中介的作用
2.靜態(tài)代理
靜態(tài)代理就是硬編碼,在編碼的過程中就已經(jīng)知道要代理的對(duì)象厂榛,最常見的就是controller盖矫、service、dao 就是靜態(tài)代理的一種實(shí)現(xiàn)击奶。
/**
* create by yufeng on 2021/7/4 14:00
*/
public interface IPerson {
void findLove();
}
/**
* create by yufeng on 2021/7/4 14:00
*/
public class ZhangSan implements IPerson {
public void findLove() {
System.out.println("兒子要求:膚白貌美大長(zhǎng)腿");
}
}
/**
* create by yufeng on 2021/7/4 14:00
*/
public class ZhangLaosan implements IPerson {
private ZhangSan zhangsan;
public ZhangLaosan(ZhangSan zhangsan) {
this.zhangsan = zhangsan;
}
public void findLove() {
System.out.println("張老三開始物色");
zhangsan.findLove();
System.out.println("開始交往");
}
}
/**
* create by yufeng on 2021/7/4 14:00
*/
public class Test {
public static void main(String[] args) {
ZhangLaosan zhangLaosan = new ZhangLaosan(new ZhangSan());
zhangLaosan.findLove();
}
}
執(zhí)行結(jié)果:
張老三開始物色
兒子要求:膚白貌美大長(zhǎng)腿
開始交往
3.動(dòng)態(tài)代理
3.1jdk動(dòng)態(tài)代理
靜態(tài)代理的弊端辈双,就是靜態(tài)代理只能手動(dòng)增加,如果代理類增加了新的方法柜砾,代理類也要同步增加辐马,違背了開閉原則
動(dòng)態(tài)代理在代碼允許的過程中動(dòng)態(tài)生成代碼的形式,取消了對(duì)被代理類的擴(kuò)展限制,遵循開閉原則喜爷。
/**
* create by yufeng on 2021/7/4 14:33
*/
public interface IPerson {
void findLove();
void buyInsure();
}
/**
* create by yufeng on 2021/7/4 14:33
*/
public class Zhangsan implements IPerson {
public void findLove() {
System.out.println("張三要求:膚白貌美大長(zhǎng)腿");
}
public void buyInsure() {
System.out.println("30萬");
}
}
/**
* create by yufeng on 2021/7/4 14:33
*/
public class ZhaoLiu implements IPerson {
public void findLove() {
System.out.println("趙六要求:有車有房學(xué)歷高");
}
public void buyInsure() {
}
}
/**
* create by yufeng on 2021/7/4 14:33
*/
public class JdkMeipo implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target,args);
after();
return result;
}
private void after() {
System.out.println("雙方同意,開始交往");
}
private void before() {
System.out.println("我是媒婆萄唇,已經(jīng)收集到你的需求檩帐,開始物色");
}
}
/**
* create by yufeng on 2021/7/4 14:33
*/
public class Test {
public static void main(String[] args) {
JdkMeipo jdkMeipo = new JdkMeipo();
IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());
zhangsan.findLove();
zhangsan.buyInsure();
IPerson zhaoliu = jdkMeipo.getInstance(new ZhaoLiu());
zhaoliu.findLove();
}
}
執(zhí)行結(jié)果:
我是媒婆,已經(jīng)收集到你的需求另萤,開始物色
張三要求:膚白貌美大長(zhǎng)腿
雙方同意湃密,開始交往
我是媒婆,已經(jīng)收集到你的需求四敞,開始物色
30萬
雙方同意泛源,開始交往
我是媒婆,已經(jīng)收集到你的需求忿危,開始物色
趙六要求:有車有房學(xué)歷高
雙方同意达箍,開始交往
動(dòng)態(tài)生成代理類,后面如有王五要相親铺厨,是不需要改動(dòng)代理類的缎玫。
3.2cglib 動(dòng)態(tài)代理
/**
* create by yufeng on 2021/7/4 14:33
*/
public class Customer {
public void findLove(){
System.out.println("兒子要求:膚白貌美大長(zhǎng)腿");
}
}
/**
* create by yufeng on 2021/7/4 15:33
*/
public class CGlibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
//相當(dāng)于Proxy,代理的工具類
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆解滓,我要給你找對(duì)象赃磨,現(xiàn)在已經(jīng)確認(rèn)你的需求");
System.out.println("開始物色");
}
private void after(){
System.out.println("OK的話,準(zhǔn)備辦事");
}
}
/**
* create by yufeng on 2021/7/4 14:33
*/
public class CglibTest {
public static void main(String[] args) {
try {
Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
System.out.println(obj);
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.3兩種動(dòng)態(tài)代理的區(qū)別
JDK是采用讀取接口的信息洼裤;CGLib覆蓋父類方法邻辉。目的都是動(dòng)態(tài)生成一個(gè)新的類,去實(shí)現(xiàn)增加代碼邏輯的功能腮鞍。
JDK對(duì)應(yīng)目標(biāo)類來說必須實(shí)現(xiàn)某個(gè)接口值骇;CGLib可以代理任意一個(gè)普通的類,沒有特殊要求缕减。
CGLib生成的代理邏輯更復(fù)雜雷客,效率調(diào)用效率更高,生成一個(gè)抱哈所有邏輯的FastClass桥狡,不需要反射
JDK Proxy生成代理的邏輯簡(jiǎn)單搅裙,執(zhí)行效率相對(duì)要低,每次都要反射動(dòng)態(tài)調(diào)用
但是CGLib 有需要注意的地方裹芝,CGLib不能代理final的方法