JDK 動態代理原理

2023-10-19 21:03:11

代理模式

使用者端不直接存取目標物件,需要通過第三者來實現間接存取物件

代理物件在使用者端和目標物件之間起中介作用,能夠遮蔽目標物件不想讓使用者端知道的內容,或增加額外的服務

動態代理

JDK 動態代理:基於介面,利用 JDK API 動態地在記憶體中構建代理物件,從而實現目標物件的代理功能。稱為 JDK 代理或介面代理。

JDK 動態代理例子

  • MapperInvocationHandler 實現 InvocationHandler 介面,實現 invoke 方法,該方法最終是代理類增強的目標類方法
  • JDKProxyFactory 用於生成代理物件的工廠,通過呼叫 Proxy.newProxyInstance 方法生成代理物件
  • UserMapper 目標類,JDK 代理的目標類必須實現某個介面
  • IUserMapper 目標類介面

MapperInvocationHandler

public class MapperInvocationHandler implements InvocationHandler {
    // 動態的目標物件
    private Object target;

    public MapperInvocationHandler(Object target) {
        this.target = target;
    }
    /**
     * 增強方法
     * @param proxy 代理範例
     * @param method 目標方法
     * @param args 目標方法引數
     * @return 返回值
     * @throws Throwable 異常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("=========JDK 動態代理前置增強=========");
        method.invoke(target, args);
        System.out.println("=========JDK 動態代理後置增強=========");
        return null;
    }
}

JDKProxyFactory

public class JDKProxyFactory {
    // 動態的目標物件
    private Object target;

    public JDKProxyFactory(Object target) {
        this.target = target;
    }

    // 為目標物件生成代理物件
    public Object getTargetProxy(){
        return Proxy.newProxyInstance(
                // 目標物件使用的類載入器
                target.getClass().getClassLoader(),
                // 目標物件實現的介面
                target.getClass().getInterfaces(),
                // 事件處理器
                new MapperInvocationHandler(target)
        );
    }
}

IUserMapper

public interface IUserMapper {
    void save();
}

UserMapper

public class UserMapper implements IUserMapper {
    @Override
    public void save() {
        System.out.println("儲存使用者資料");
    }
}

Client

public class Client {
    public static void main(String[] args) {
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(new UserMapper());
        IUserMapper userMapperProxy = (IUserMapper) jdkProxyFactory.getTargetProxy();
        userMapperProxy.save();
    }
}

執行結果

=========JDK 動態代理前置增強=========
儲存使用者資料
=========JDK 動態代理後置增強=========

Process finished with exit code 0

JDK 動態代理原理