Java的静态代理和动态代理

48 阅读2分钟

代理模式

可以通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

image.png

静态代理

缺点

  • 冗余:代理对象需要实现和目标对象一致的接口。
  • 扩展性:一旦接口新增方法,代理对象也需要更新。
// 1. 定义接口
public interface Calculator {
    int add(int a, int b);
}

// 2. 真实实现类
public class RealCalculator implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

// 3. 静态代理类
public class CalculatorStaticProxy implements Calculator {
    private final Calculator real;  // 持有真实对象

    public CalculatorStaticProxy(Calculator real) {
        this.real = real;
    }

    @Override
    public int add(int a, int b) {
        // 前置操作
        System.out.println("【StaticProxy】准备计算:" + a + " + " + b);
        // 调用真实对象的方法
        int result = real.add(a, b);
        // 后置操作
        System.out.println("【StaticProxy】计算完毕,结果:" + result);
        return result;
    }
}

// 4. 客户端调用
public class Client {
    public static void main(String[] args) {
        Calculator realCalc = new RealCalculator();
        Calculator proxyCalc = new CalculatorStaticProxy(realCalc);
        int sum = proxyCalc.add(3, 5);
        // 控制台输出:
        // 【StaticProxy】准备计算:3 + 5
        // 【StaticProxy】计算完毕,结果:8
    }
}

动态代理

  • 使用JDK API反射实现
    • 无需手动编写代理类,由InvocationHandler处理
    • 用了反射,性能略低
    • 扩展性好,新增功能不用更改代理类
    • 常用于AOP,权限校验,日志等场景。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 1. 业务接口及实现(同静态代理示例中的 Calculator & RealCalculator)

// 2. 自定义 InvocationHandler
public class CalculatorDynamicHandler implements InvocationHandler {
    private final Object target;  // 真实对象

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置操作
        System.out.println("【DynamicProxy】调用前:" + method.getName() + ", 参数:" + args[0] + ", " + args[1]);
        // 反射调用真实对象的方法
        Object result = method.invoke(target, args);
        // 后置操作
        System.out.println("【DynamicProxy】调用后,结果:" + result);
        return result;
    }
}

// 3. 客户端生成并使用代理
public class Client {
    public static void main(String[] args) {
        Calculator realCalc = new RealCalculator();

        // 动态生成代理对象
        Calculator proxyCalc = (Calculator) Proxy.newProxyInstance(
            realCalc.getClass().getClassLoader(),
            new Class<?>[]{Calculator.class},
            new CalculatorDynamicHandler(realCalc)
        );

        int sum = proxyCalc.add(7, 2);
        // 控制台输出:
        // 【DynamicProxy】调用前:add, 参数:7, 2
        // 【DynamicProxy】调用后,结果:9
    }
}
  • CGLIB代理:不依赖接口,直接对类进行代理,但是目标被代理类以及方法,不能为final。