在 Java 编程中,代理模式是一种重要的设计模式,通常用于控制对某个对象的访问。代理模式可以分为三种主要类型:静态代理、JDK 动态代理和 CGLIB 代理。下面我们将分别解析这三种代理模式及其优缺点,并提供代码示例。

一、静态代理

静态代理是在编译时创建代理类。在使用静态代理时,我们需要为每一个被代理的类编写一个代理类。静态代理的优点是比较简单易懂,但缺点在于针对每个被代理的类都要写一个代理类,增加了代码的重复性。

示例代码

// 被代理类
interface RealSubject {
    void request();
}

class RealSubjectImpl implements RealSubject {
    @Override
    public void request() {
        System.out.println("RealSubject: Request.");
    }
}

// 代理类
class ProxySubject implements RealSubject {
    private RealSubject realSubject;

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

    @Override
    public void request() {
        System.out.println("ProxySubject: Before request.");
        realSubject.request();
        System.out.println("ProxySubject: After request.");
    }
}

// 测试
public class StaticProxyTest {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubjectImpl();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

二、JDK 动态代理

JDK 动态代理支持在运行时创建代理类。它要求被代理的类必须实现接口。JDK 动态代理是通过 java.lang.reflect.Proxy 类实现的,灵活性较高。

示例代码

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

// 被代理类接口
interface Subject {
    void request();
}

// 被代理类实现
class SubjectImpl implements Subject {
    @Override
    public void request() {
        System.out.println("SubjectImpl: Request.");
    }
}

// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy: Before request.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy: After request.");
        return result;
    }
}

// 测试
public class DynamicProxyTest {
    public static void main(String[] args) {
        Subject realSubject = new SubjectImpl();
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                new DynamicProxyHandler(realSubject));

        proxySubject.request();
    }
}

三、CGLIB 代理

CGLIB(Code Generation Library)是一个强大的、高性能的代码生成包,可以在运行时动态创建被代理类的子类。这种代理方式不要求被代理类实现接口,适合于不使用接口的场景。

示例代码

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 被代理类
class CglibSubject {
    public void request() {
        System.out.println("CglibSubject: Request.");
    }
}

// CGLIB 代理处理器
class CglibProxy implements MethodInterceptor {
    private Object target;

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

    @Override
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CglibProxy: Before request.");
        Object result = proxy.invoke(target, args);
        System.out.println("CglibProxy: After request.");
        return result;
    }
}

// 测试
public class CglibProxyTest {
    public static void main(String[] args) {
        CglibSubject subject = new CglibSubject();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibSubject.class);
        enhancer.setCallback(new CglibProxy(subject));
        CglibSubject proxySubject = (CglibSubject) enhancer.create();
        proxySubject.request();
    }
}

四、总结对比

  1. 静态代理
  2. 优点:简单易懂;实施成本低。
  3. 缺点:类的数量增加;缺乏灵活性。

  4. JDK 动态代理

  5. 优点:灵活性高;可以在运行时生成代理。
  6. 缺点:只能代理实现了接口的类;性能相对较低。

  7. CGLIB 代理

  8. 优点:可以代理没有实现接口的类;性能高于 JDK 动态代理。
  9. 缺点:会生成子类,不会代理 final 类;引入了外部依赖。

综上所述,选择合适的代理方式需要根据具体的应用场景和需求来决定。对于简单的场景,静态代理就足够用了;对于需要动态生成代理的场景,JDK 动态代理是较好的选择;而在需要代理没有接口的类时,CGLIB 代理表现较佳。

点赞(0) 打赏

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部