java代理模式与动态代理模式详解


在Java中,代理模式(Proxy Pattern)是一种结构型设计模式,它用于为其他对象提供一种代理以控制对这个对象的访问。代理模式主要分为静态代理和动态代理两种形式。

### 静态代理

静态代理是在编译时就确定具体类的一种代理方式。它通常通过创建一个代理类,这个代理类实现了与目标对象相同的接口,并在其方法内部调用目标对象的方法来实现对目标对象的代理。

**示例代码**(简单版):


// 接口
interface Image {
    void display();
}

// 目标对象
class RealImage implements Image {
    private String filename;

    RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }

    private void loadFromDisk(String filename) {
        System.out.println("Loading " + filename);
    }
}

// 代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;

    ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 使用
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        image.display();
    }
}

### 动态代理

动态代理是在运行时动态地创建代理类的一种代理方式。它主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。动态代理通常用于当我们不知道目标对象的具体类时,或者需要频繁地创建代理类时。

**示例代码**(基于接口的动态代理):


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Image {
    void display();
}

class RealImage implements Image {
    private String filename;

    RealImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}

class ImageInvocationHandler implements InvocationHandler {
    private Object target;

    ImageInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在方法调用之前可以做一些处理
        System.out.println("Before method " + method.getName());

        // 调用目标对象的方法
        Object result = method.invoke(target, args);

        // 在方法调用之后可以做一些处理
        System.out.println("After method " + method.getName());

        return result;
    }

    // 获取动态代理的实例
    @SuppressWarnings("unchecked")
    public static <T> T getProxyInstance(T target, Class<T> interfaceType) {
        return (T) Proxy.newProxyInstance(
            interfaceType.getClassLoader(),
            new Class<?>[]{interfaceType},
            new ImageInvocationHandler(target)
        );
    }
}

// 使用
public class DynamicProxyPatternDemo {
    public static void main(String[] args) {
        Image realImage = new RealImage("test.jpg");
        Image proxyImage = ImageInvocationHandler.getProxyInstance(realImage, Image.class);
        proxyImage.display();
    }
}

这两个示例分别展示了静态代理和动态代理的基本用法。静态代理在编译时确定代理关系,而动态代理在运行时确定代理关系,提供了更高的灵活性和可扩展性。