給目標對象提供一個代理對象,并由代理對象控制對目標對象的引用。其中代理對象起到中介作用,用于連接客戶端和目標對象。例如:電腦桌面的快捷方式。電腦對某個程序提供一個快捷方式(代理對象),快捷方式連接客戶端和程序,客戶端通過操作快捷方式就可以操作那個程序。
通過引入代理對象的方式來間接訪問目標對象,防止直接訪問目標對象給系統帶來的不必要復雜性。
步驟1: 創建抽象對象接口(Subject):聲明你(真實對象)需要讓代購(代理對象)幫忙做的事(買Mac)
public interface Subject { ?
public void buyMac();
}
步驟2: 創建真實對象類(RealSubject),即”我“
public class RealSubject implement Subject{
? ?@Override
? public void buyMac() { ?
? ? ? System.out.println(”買一臺Mac“); ?
? } ?
}
步驟3:創建代理對象類(Proxy),即”代購“,并通過代理類創建真實對象實例并訪問其方法
public class Proxy ?implements Subject{
??
? ?@Override
? public void buyMac{ ??
? ? //引用并創建真實對象實例,即”我“
? ? RealSubject realSubject = new RealSubject();
? ? //調用真實對象的方法,進行代理購買Mac
? ? realSubject.buyMac();
? ? //代理對象額外做的操作
? ? this.WrapMac();
? }
? ?public void WrapMac(){
? ? System.out.println(”用盒子包裝好Mac“); ?
? }
}
步驟4:客戶端調用
public class ProxyPattern {
? ? public static void main(String[] args){
? ? Subject proxy = new Proxy();
? ? proxy.buyMac();
? ? }? ? ??
}
結果輸出
買一臺Mac
用盒子包裝好Mac
優點
協調調用者和被調用者,降低了系統的耦合度
代理對象作為客戶端和目標對象之間的中介,起到了保護目標對象的作用
缺點
由于在客戶端和真實主題之間增加了代理對象,因此會造成請求的處理速度變慢;
實現代理模式需要額外的工作(有些代理模式的實現非常復雜),從而增加了系統實現的復雜度。
在靜態代理模式中一個靜態代理只服務一種類型的目標對象,若要服務多類型的目標對象,則需要為每種目標對象都實現一個靜態代理對象。在目標對象較多的情況下,若采用靜態代理,則會出現 靜態代理對象量多、代碼量大,從而導致代碼復雜的問題。
動態代理就是,在程序運行期,創建目標對象的代理對象,并對目標對象中的方法進行功能性增強的一種技術。在生成代理對象的過程中,目標對象不變,代理對象中的方法是目標對象方法的增強方法。可以理解為運行期間,對象中方法的動態攔截,在攔截方法的前后執行功能操作。
代理類在程序運行期間,創建的代理對象稱之為動態代理對象。這種情況下,創建的代理對象,并不是事先在Java代碼中定義好的。而是在運行期間,根據我們在動態代理對象中的“指示”,動態生成的。也就是說,你想獲取哪個對象的代理,動態代理就會為你動態的生成這個對象的代理對象。動態代理可以對被代理對象的方法進行功能增強。有了動態代理的技術,那么就可以在不修改方法源碼的情況下,增強被代理對象的方法的功能,在方法執行前后做任何你想做的事情。
1)動態代理不需要顯式實現與目標對象類(RealSubject)相同的接口,而是將這種實現推遲到程序運行時由 JVM來實現。即:在使用時再創建動態代理類 & 實例;
2)通過Java 反射機制的method.invoke(),通過調用動態代理類對象方法,從而自動調用目標對象的方法。
優點
1)只需要1個動態代理類就可以解決創建多個靜態代理的問題,避免重復、多余代碼;
2)更強的靈活性;
缺點
1)效率低:相比靜態代理中直接調用目標對象方法,動態代理則需要先通過Java反射機制 從而間接調用目標對象方法。
2)應用場景局限:Java 的單繼承特性(每個代理類都繼承了 Proxy 類),即只能針對接口創建代理類,不能針對類創建代理類。
日志記錄、性能統計、安全控制、異常處理等。
1.創建接口,定義目標類需要完成的功能
2.創建目標類,實現接口。
3.創建InvocationHandler接口的實現類。在invoke方法中完成代理類的功能。
目標方法的調用
功能增強
4.使用Proxy類中靜態方法Proxy.newProxyInstance完成代理類對象的創建,返回代理對象,并把返回值轉為接口類型。
public class JDKDynamicProxy {
public static void main(String[] args) {
CAProxy caProxy = new CAProxy();
IA instance = (IA) caProxy.getInstance(new CA());
instance.say();
instance.fly();
}
}
interface IA{
void say();
void fly();
}
class CA implements IA{
@Override
public void say() {
System.out.println("I am class CA");
}
@Override
public void fly() {
System.out.println("I can fly");
}
}
class CAProxy implements InvocationHandler{
private Object target;
public Object getInstance(Object object){
this.target = object;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("I am proxy!");
Object result = method.invoke(target, args);
return result;
}
}
public class CglibDynamicProxy {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
A a = (A) cglibProxy.getInstance(new A());
a.say();
}
}
class A {
public void say(){
System.out.println("I am A");
}
}
class CglibProxy implements MethodInterceptor{
private Object target;
public Object getInstance(Object object){
this.target = object;
Enhancer enhancer = new Enhancer();
// 設置父類為實例類
enhancer.setSuperclass(this.target.getClass());
// 回調方法
enhancer.setCallback(this);
// 創建代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("I am cglib proxy!");
Object result = method.invoke(target, objects);
return result;
}
}