代理模式

静态代理

静态代理是一种设计模式,用于在不改变目标对象的情况下,增加对目标对象的控制或功能。它的基本思想是创建一个代理类,该类实现与目标类相同的接口,并在其方法中调用目标对象的方法

优点:

  • 增强功能:可以在不改变目标类的情况下,增强其功能。
  • 代码复用:通过代理类可以重用目标类的代码。

缺点:

  • 代码膨胀:每增加一个目标类,就需要增加一个对应的代理类,导致代码量增大。
  • 灵活性差:代理类在编译时就被确定,不能动态改变。

示例:

// 定义接口
interface Subject {
    void request();
}

// 目标类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

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

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

    @Override
    public void request() {
        // 增强功能:在请求前后添加日志
        System.out.println("ProxySubject: Logging before request.");
        realSubject.request();
        System.out.println("ProxySubject: Logging after request.");
    }
}

// 测试
public class StaticProxyDemo {
    public static void main(String[] args) {
        // 创建代理类,ProxySubject 代理的是 Subject 类,如果不是 Subject 就不能代理,就要重新创建一个代理类
        Subject proxy = new ProxySubject();
        // 调用代理类的方法,内部还是会调用目标类的方法,但是代理方法增强过
        proxy.request();
    }
}

JDK 动态代理

静态代理最大的弊端就是每增加一种目标类就要增加一种代理类,所以静态代理除了特定的场景几乎不适用

使用 java.lang.reflect.Proxy#newProxyInstance 来创建代理类,这个方法一共三个参数:

  1. 目标类的类加载器

  2. 目标类实现的接口

  3. 执行处理器,是一个接口 InvocationHandler,里面只有一个方法(函数式接口)

    // 创建目标对象
    User user = new User();
    
    // 代理类
    User userProxy = (User) Proxy.newProxyInstance(
            user.getClass().getClassLoader(), // 目标类类加载器
            user.getClass().getInterfaces(),  // 目标类接口
            new InvocationHandler() { // 执行处理器,可以使用 lambda 表达式
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 可以在方法执行前后增强、args 是参数可以动态修改 等
    
                    // 执行目标方法
                    Object result = method.invoke(user, args);
                    // 返回目标方法执行结果
                    return result;
                }
            }
    );
    
    // 使用代理类调用方法
    userProxy.getName();
    

再一个示例

定义多个接口:

public interface SubjectA {
    void requestA();
}

public interface SubjectB {
    void requestB();
}

接口实现类:

public class RealSubjectA implements SubjectA {
    @Override
    public void requestA() {
        System.out.println("RealSubjectA: Handling request A.");
    }
}

public class RealSubjectB implements SubjectB {
    @Override
    public void requestB() {
        System.out.println("RealSubjectB: Handling request B.");
    }
}

执行处理器:

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

public class DynamicInvocationHandler implements InvocationHandler {
    private Object target;

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

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

使用:

import java.lang.reflect.Proxy;

public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 代理 RealSubjectA
        RealSubjectA realSubjectA = new RealSubjectA();
        SubjectA proxyA = (SubjectA) Proxy.newProxyInstance(
                realSubjectA.getClass().getClassLoader(),
                realSubjectA.getClass().getInterfaces(),
                new DynamicInvocationHandler(realSubjectA) // 执行处理器使用都是同一个 DynamicInvocationHandler
        );
        proxyA.requestA();

        // 代理 RealSubjectB
        RealSubjectB realSubjectB = new RealSubjectB();
        SubjectB proxyB = (SubjectB) Proxy.newProxyInstance(
                realSubjectB.getClass().getClassLoader(),
                realSubjectB.getClass().getInterfaces(),
                new DynamicInvocationHandler(realSubjectB) // // 执行处理器使用都是同一个 DynamicInvocationHandler
        );
        proxyB.requestB();
    }
}

CGLIB 动态代理

JDK 动态代理要求目标类必须实现接口,如果目标类没有实现接口就要使用 CGLIB 动态代理,是三方实现的,所以要引入依赖

依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

目标类:

public class UserService {
    public void addUser(String user) {
        System.out.println("Adding user: " + user);
    }
}

创建 CGLIB 代理类:

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

public class UserServiceProxy implements MethodInterceptor {

    // 创建代理对象的方法
    public Object createProxy(Class<?> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass); // 设置要代理的类
        enhancer.setCallback(this); // 设置回调
        return enhancer.create(); // 创建代理对象
    }

    @Override
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = proxy.invokeSuper(obj, args); // 调用目标类的方法
        System.out.println("After method: " + method.getName());
        return result;
    }
}

使用:

public class CGLIBProxyDemo {
    public static void main(String[] args) {
        // 创建 CGLIB 代理
        UserServiceProxy proxy = new UserServiceProxy();
        UserService userServiceProxy = (UserService) proxy.createProxy(UserService.class);

        // 使用代理对象调用方法
        userServiceProxy.addUser("John Doe");
    }
}
posted @   CyrusHuang  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示