Java 开发必看!代理设计模式让你的代码优雅又高效

在 Java 项目的全生命周期开发进程中,随着业务逻辑复杂度呈几何级数增长,代码的高耦合性问题日益凸显,系统维护成本急剧攀升。当开发人员试图对某一功能模块进行局部优化时,往往会引发连锁反应,导致其他模块出现意想不到的异常,形成难以根治的技术债务。而代理设计模式作为一种经典的软件设计模式,为解决此类问题提供了有效的技术方案。

在互联网大厂的后端开发领域,代码质量与系统可维护性始终是技术团队关注的核心指标。面对大规模、高并发的业务场景,以及频繁的团队协作开发需求,如何构建具备良好扩展性与稳定性的软件架构,成为每一位 Java 后端开发工程师需要深入思考的重要课题。代理设计模式通过引入代理对象,在不修改目标对象源代码的前提下,实现对目标对象的功能增强与访问控制,有效提升了系统的灵活性与可维护性。

Java 代理设计模式的实现体系

在 Java 技术栈中,代理设计模式主要通过静态代理和动态代理两种方式实现,每种方式都有其独特的技术特性与应用场景。

静态代理:编译期确定的代理实现

静态代理是在编译阶段就确定代理关系的实现方式。以图片展示功能模块开发为例,首先需要定义一个抽象的目标对象接口Image,该接口明确规定了实现类需要具备的行为契约,包含display方法用于完成图片展示操作:

public interface Image {
    void display();
}

接着创建具体的目标对象实现类RealImage,该类实现Image接口,并在构造函数中模拟从磁盘加载图片的实际操作,同时实现display方法用于展示图片:

public class RealImage implements Image {
    private String filename;

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

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

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

然后创建代理对象类ProxyImage,同样实现Image接口。在ProxyImage的display方法中,通过条件判断实现对目标对象RealImage的延迟加载,并在调用目标对象方法前后,可灵活添加日志记录、权限校验等增强功能:

public class ProxyImage implements ImageProxy {
    private String filename;
    private Image realImage;

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

    @Override
    public void display() {
        System.out.println("开始执行图片显示代理逻辑");
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
        System.out.println("图片显示代理逻辑执行完毕");
    }
}

若代理对象存在特殊功能需求,可定义代理对象接口ImageProxy,该接口继承自目标对象接口Image,为代理对象的扩展功能提供契约定义。

动态代理:运行时生成的灵活代理机制

动态代理是在程序运行阶段动态生成代理类的实现方式,相比静态代理具有更高的灵活性与扩展性,主要包括 JDK 动态代理和 CGLIB 动态代理两种技术方案。

JDK 动态代理:基于接口的代理实现

JDK 动态代理通过实现InvocationHandler接口,并重写invoke方法来实现代理逻辑。以方法执行时间统计功能为例,创建TimeHandler类实现InvocationHandler接口,在invoke方法中通过获取系统时间戳,精确计算目标方法的执行时长:

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

public class TimeHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long endTime = System.currentTimeMillis();
        System.out.println("方法" + method.getName() + "执行时间:" + (endTime - startTime) + "毫秒");
        return result;
    }
}

在主程序中,通过Proxy.newProxyInstance方法,传入类加载器、目标对象实现的接口列表以及InvocationHandler实例,动态生成代理对象,实现对目标对象方法执行时间的自动统计:

import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        Image realImage = new RealImage("image.jpg");
        InvocationHandler h = new TimeHandler(realImage);
        Class<?> cls = realImage.getClass();
        Image proxyImage = (Image) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
        proxyImage.display();
    }
}

CGLIB 动态代理:基于类继承的代理实现

CGLIB 动态代理通过继承目标类的方式实现代理功能,需要实现MethodInterceptor接口,并通过Enhancer类动态生成代理类。以火车行驶功能的日志记录需求为例,首先定义目标类Train:

public class Train {
    public void move() {
        System.out.println("火车行驶中…");
    }
}

然后创建代理类CGLibProxy实现MethodInterceptor接口,在intercept方法中实现日志记录逻辑,通过调用MethodProxy.invokeSuper方法执行目标对象的原始方法:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CGLibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class<?> clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("日志开始");
        proxy.invokeSuper(obj, args);
        System.out.println("日志结束");
        return null;
    }
}

在测试代码中,通过CGLibProxy生成代理对象,并调用目标方法,实现日志记录功能:

public class Main {
    public static void main(String[] args) {
        CGLibProxy proxy = new CGLibProxy();
        Train train = (Train) proxy.getProxy(Train.class);
        train.move();
    }
}

总结

静态代理与动态代理在实现机制与应用场景上各有优劣。静态代理具有明确的编译期契约,代码结构清晰,适用于代理关系相对稳定的业务场景;而动态代理凭借其运行时动态生成代理类的特性,在面对频繁变化的业务需求时,展现出更高的灵活性与扩展性。

在实际的 Java 后端开发项目中,开发人员应根据具体的业务需求与系统架构特点,合理选择代理设计模式的实现方式。通过正确运用代理设计模式,不仅能够有效降低代码耦合度,提升系统的可维护性,还能为系统功能的扩展与优化提供有力的技术支持。希望广大 Java 开发者能够积极实践代理设计模式,在实际项目中充分发挥其技术优势。如果在使用过程中有任何技术疑问或实践经验,欢迎在评论区进行技术交流与分享,共同推动 Java 后端开发技术的进步与发展。

原文链接:,转发请注明来源!