Java中的动态代理与静态代理的区别和使用

动态代理和静态代理是Java中常用的两种代理模式。它们都可以用于实现对象间的间接访问,但在实现方式和使用场景上有一些区别。

静态代理

静态代理是指在编译时就已经确定代理类的代理对象和被代理对象的关系。在静态代理中,代理类需要实现与被代理类相同的接口,并持有一个被代理对象的引用。

下面是一个简单的静态代理的示例:

interface Subject {
    void doSomething();
}

class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}

class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void doSomething() {
        System.out.println("ProxySubject do something before");
        realSubject.doSomething();
        System.out.println("ProxySubject do something after");
    }
}

public class StaticProxyDemo {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.doSomething();
    }
}

在上面的示例中,接口Subject定义了一个doSomething的方法,被代理类RealSubject实现了该接口,并提供了具体的实现逻辑。代理类ProxySubject也实现了Subject接口,并持有了一个RealSubject对象的引用。在代理类的doSomething方法中,可以在调用被代理对象的doSomething方法前后添加一些其他逻辑。

使用静态代理的优点是可以在不修改原有代码的情况下,通过代理类来扩展原有的功能。但缺点是每个被代理类都需要对应一个代理类,当有多个被代理类时,需要编写大量的代理类代码,且会导致类的数量增加。

动态代理

相比于静态代理,动态代理在运行时才确定代理对象和被代理对象的关系。Java中提供了java.lang.reflect包来实现动态代理。动态代理使用一个代理类来代理一个或多个接口,通过InvocationHandler接口和Proxy类来实现。

下面是一个简单的动态代理的示例:

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

interface Subject {
    void doSomething();
}

class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}

class DynamicProxy implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy do something before");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy do something after");
        return result;
    }
}

public class DynamicProxyDemo {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicProxy(realSubject);
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
        proxySubject.doSomething();
    }
}

在上面的示例中,接口Subject和类RealSubject与静态代理中的一样。动态代理类DynamicProxy实现了InvocationHandler接口,该接口只有一个invoke方法,用于处理代理对象的方法调用。在invoke方法中,可以在调用被代理对象的方法前后添加一些其他逻辑。

DynamicProxyDemo类的main方法中,首先创建了被代理对象RealSubject,然后创建了DynamicProxy对象,传入了被代理对象。接下来使用Proxy.newProxyInstance方法创建代理对象,该方法接收三个参数:被代理对象的类加载器、被代理对象实现的接口和InvocationHandler对象。最后通过代理对象调用doSomething方法,实际上会调用DynamicProxy中的invoke方法。

使用动态代理的优点是可以在运行时动态地创建代理对象,不需要为每个被代理对象编写独立的代理类。同时,动态代理可以更加灵活地处理代理逻辑,可以代理多个接口,并且可以通过InvocationHandler实现动态地修改代理逻辑。

使用场景

静态代理和动态代理在使用场景上有一些差异。

静态代理适用于以下场景:

  • 代理对象和被代理对象的关系在编译时已经确定。
  • 需要对被代理对象进行简单的功能扩展。
  • 代理类的数量相对较少。

动态代理适用于以下场景:

  • 代理对象和被代理对象的关系在运行时才确定。
  • 需要对被代理对象进行复杂的功能扩展。
  • 代理类的数量较多,且可以通过动态代理统一管理。

总之,动态代理和静态代理都是Java中常用的代理模式。它们在实现方式和使用场景上有一些区别,根据具体的需求选择合适的代理方式可以帮助我们更好地组织和管理代码。