Java程序中的代理作用和應用場景及實現


The role of proxy, application scenarios, and implementation in Java programs.

代理是程序設計和開發時頻繁使用的技術,可以提高程序靈活性和可擴展性。

1 代理作用

  1. 在不修改原代碼的基礎上,擴展和增強實現;
  2. 代碼解耦,在代理中通過參數可以判斷真實類,做出不同的響應或調用,靈活方便;
  3. 隱藏部分實現過程和細節。

2 應用場景

java_proxy

ICar接口類,有一個drive方法,傳入speed(速度)行駛,現在已經有Mitsubishi(三菱車)和Bwm(寶馬車)實現了接口,隨着業務發展,可能有更多的車加入;程序穩健運行一段時間后,針對不同的車發現了不同的問題需要處理,比如Mitsubishi車drive前必須檢查和保證冷卻液充足;Bwm車drive前必須檢查和保證機油充足;由於改寫ICar接口可能影響到其它的車;如果有很多的車要處理,更改實現類可能需要花費大量時間,此時可以通過代理類擴展和增強。

java_proxy

在代理類(CarProxy)中通過carCheck方法實現對不同汽車檢查,檢查通過后drive汽車,從而實現對原有代碼增強。

3 代理的實現

3.1 靜態代理

靜態代理的思想:代理類和其它汽車類一樣實現接口類,在重寫方法里實現擴展或增強,並調要汽車類實現。

//寶馬汽車實現類
class Bwm implements ICar {
    public void drive(int speed) {
        System.out.println("Bwm drive with speed:"+speed);
    }
//三菱汽車實現類   
class Mitsubishi implements ICar {
    public void drive(int speed) {
        System.out.println("Mitsubishi drive with speed:"+speed);
    }

//汽車代理類
public class CarProxy implements ICar {
    private ICar carTarget;
    public CarProxy(ICar carTarget){
        this.carTarget=carTarget;
    }
    // 車輛檢查
    private boolean carCheck() {
        if(this.carTarget instanceof Mitsubishi){ //判斷汽車類型
            System.out.println("Mitsubishi 檢查冷卻液完成。");
            return true;
        }else if(this.carTarget instanceof Bwm){
            System.out.println("Bwm 檢查機油完成。");
            return true;
        }else{
            System.out.println("該車不需要檢查。");
            return true;
        }
    }

    /** 駕駛
     * @param speed 速度
     */
    public void drive(int speed) {
        if(carCheck()){ //檢查通過后drive
            carTarget.drive(speed); //調用汽車類
        }
    }
}

在CarProxy代理類中,增加了對不同汽車的檢查方法(carCheck),當汽車檢查通過后調用(drive)方法駕駛汽車。這樣代理類便實現了對三菱和寶馬車的擴展,調用時傳入ICar實現類對象;

new CarProxy(new Mitsubishi()).drive(80); //drive 三菱車
new CarProxy(new Bwm()).drive(100); //drive 寶馬車

運行輸出;

Mitsubishi 檢查冷卻液完成。
Mitsubishi drive with speed:80
Bwm 檢查機油完成。
Bwm drive with speed:100

3.1.1 缺點

接口類變化會影響實現類和代理類;比如方法修改返回值、參數類型、增加方法,實現類和代理類都需要修改。

3.2 動態代理

Java 提供(java.lang.reflect.InvocationHandler)代理實例接口,代理類實現該接口關聯調用處理程序的方法(invoke),當在代理實例調用方法時,方法調用被編碼(encoded)並分配給其調用處理程序的方法。

public class DynamicProxy implements InvocationHandler{
    Object carTarget;

   //車輛檢查
   private boolean carCheck() {
       if(this.carTarget instanceof Mitsubishi){
            System.out.println("Mitsubishi 檢查冷卻液完成。");
            return true;
       }else if(this.carTarget instanceof Bwm){
            System.out.println("Bwm 檢查機油完成。");
            return true;
       }else{
           System.out.println("該車不需要檢查。");
           return true;
       }
   }

    //創建代理類實例
    Object crateProxyInstance(Object carTarget) {
            this.carTarget = carTarget;
            return Proxy.newProxyInstance(carTarget.getClass().getClassLoader(), 
            carTarget.getClass().getInterfaces(),this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if(carCheck()){//汽車檢查通過后drive
                return method.invoke(carTarget,args);
            }
            return null;
        }
}

除了crateProxyInstance 和 invoke 方法外,對三菱和寶馬車的擴展(車輛檢查)與靜態類相同。調用時同樣傳入ICar實現類對象。

((ICar)new DynamicProxy().crateProxyInstance(new Mitsubishi())).drive(80);//drive 三菱車
((ICar)new DynamicProxy().crateProxyInstance(new Bwm())).drive(80);//drive 寶馬車

3.3 cglib 代理

除了java自身的代理類,還有第三方代理類,比如(cglib),通過實現方法攔截器(MethodInterceptor),在攔截方法中(intercept)調用處理程序的方法。

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CarInterceptor implements MethodInterceptor{
    Object carTarget;

   //車輛檢查
   private boolean carCheck() {
       if(this.carTarget instanceof Mitsubishi){
            System.out.println("Mitsubishi 檢查冷卻液完成。");
            return true;
       }else if(this.carTarget instanceof Bwm){
            System.out.println("Bwm 檢查機油完成。");
            return true;
       }else{
           System.out.println("該車不需要檢查。");
           return true;
       }
   }
    //攔截方法 
    @Override
    public Object intercept(Object carTarget, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        this.carTarget=carTarget;
        if(carCheck()){//汽車檢查通過后drive
            Object obj=proxy.invokeSuper(carTarget, args);
            return obj;
        }
        return null;
    }
}

最后調用時,首先實例化(Enhancer)對象啟用方法攔截器,設置方法攔截類和Superclass;

Enhancer en=new Enhancer(); 
en.setCallback(new CarInterceptor());//設置攔截類
//drive 三菱車
en.setSuperclass(new Mitsubishi().getClass());//設置superClass
((ICar) en.create()).drive(80);
//drive 寶馬車
en.setSuperclass(new Bwm().getClass());
((ICar) en.create()).drive(100);

4 總結

靜態代理更像是開發層面的實現,每次修改接口類或實現類都可能需要修改代理類,隨着程序擴展,代碼量和維護量增加;Java 提供的(java.lang.reflect.InvocationHandler)代理實例接口和第三方代理類(cglib)大大彌補了靜態類的不足,也應用在許多開源框架上,比如Spring。

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM