java设计模式:动态代理

先理解核心角色:真实世界里的转账

想象一下去银行转账:

  1. ​​Bank银行 )​​:它最核心的工作就是处理转账,比如从A账户扣钱,向B账户加钱。这是​​核心业务​​。

  2. Alipay支付宝 )​​:你平时并不直接操作银行,而是用支付宝。你登录支付宝,它帮你完成身份验证、推送通知、积分奖励等一系列操作,最后才是调用银行的底层功能完成转账。支付宝在这里就像是银行的​​代理​​。

在编程中,我们也要模拟这个过程,但希望这个"代理"能更智能、更通用。这就是动态代理要解决的问题。

什么是动态代理?------ 你的"万能业务管家"

你可以把动态代理想象成一个​​万能业务管家​​。

  • 静态代理 好比是:银行专门为"转账"业务雇了一个管家。如果银行后来又开通了"买理财"业务,就得再为"买理财"专门雇另一个管家。业务越多,管家也越多,管理起来很麻烦。
  • 动态代理​​ 则是:银行雇了一个超级聪明的AI管家。你只需要告诉这个AI管家银行的各项业务规则(比如办业务前要验证身份,办完后要记录日志),那么无论是转账、买理财、还是查余额,这个AI管家都能自动帮你处理这些通用流程,然后再去调用银行真正的核心功能。

​​它的巨大优势在于​​:银行(目标对象)只需要专注实现自己的核心业务(比如转账),所有外围的、通用的工作(如验证、日志)都交给这个"万能管家"(动态代理)统一处理。需要增加新业务时,银行本身代码不用大改,只需要告诉管家新业务的规则即可,非常灵活和高效。

动态代理的API三件套

在Java里,打造这个"万能管家"主要用到三个工具,它们都在 java.lang.reflect包里

1. ​​InvocationHandler接口(管家的工作手册)​​

这是管家的核心工作指南,里面只有一个关键方法 invoke。管家每次替银行处理任何业务时,都会严格执行这本手册。

java 复制代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 1. 业务办理前:自动执行增强功能,如身份验证
    System.out.println("【Alipay管家】验证身份与权限...");

    // 2. 办理核心业务:调用银行真正的转账方法
    Object result = method.invoke(target, args);

    // 3. 业务办理后:自动执行后续工作,如发送通知
    System.out.println("【Alipay管家】发送短信通知,赠送积分...");
    return result;
}

​​2. Proxy类(管家生成器)​​

这个类就像是管家制造机。它的 newProxyInstance方法可以根据你的要求,动态地创建一个全新的、活生生的AI管家(代理对象)。

java 复制代码
BankManager proxy = (BankManager) Proxy.newProxyInstance(
    realBank.getClass().getClassLoader(), // 使用银行的"知识库"(类加载器)
    realBank.getClass().getInterfaces(),  // 声明管家要代理的所有银行业务(接口)
    myInvocationHandler // 交给管家一本具体的工作手册(InvocationHandler实例)
);

3. Method类(具体业务指令)​​

当你说"我要转账",这个"转账"动作本身就是一个 Method对象。管家会通过它来识别并执行对应的银行核心操作。

1. 手把手代码演示:Alipay代理Bank转账

我们来把上面的比喻写成具体的代码。

第1步:定义业务规范(接口)

首先,我们要规定好银行的核心业务有哪些,也就是先定义一个接口(像一份业务合同)

java 复制代码
// 银行转账接口
public interface BankTransfer {
    void transfer(String fromAccount, String toAccount, double amount);
    
    double queryAccountInfo(String acount);
}

第2步:银行实现核心业务(真实对象)

然后,银行(真实对象)来实现这个接口,只关注最核心的转账逻辑

java 复制代码
// 真实银行,只做最核心的事
public class RealBank implements BankTransfer {
    @Override
    public void transfer(String fromAccount, String toAccount, double amount) {
        // 这是最核心的转账操作
        System.out.println("[银行核心系统] 完成转账:" + fromAccount + " -> " + toAccount + ", 金额:" + amount + "元");
    }
    
    @Override
    public double queryAccountInfo(String account) {
        System.out.println("查询账户 " + account + " 余额");
        return 10000.0; // 模拟余额
    }
}

第3步:编写管家的工作手册(调用处理器)

这是最关键的一步,我们创建"万能管家"的工作手册(InvocationHandler),所有增强功能都在这里实现

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

// Alipay的万能管家工作手册
public class AlipayInvocationHandler implements InvocationHandler {
    private Object target; // 管家代理的真实对象,比如某个银行

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1. 【前置增强】在调用真实业务前做事:身份验证、安全检查等
        System.out.println("✅ 【Alipay】身份验证通过");
        System.out.println("✅ 【Alipay】资金安全检查完成");

        // 2. 【核心操作】调用真实银行的核心转账方法
        System.out.println("🚀 【Alipay】开始执行核心转账业务...");
        Object result = method.invoke(target, args);

        // 3. 【后置增强】在调用真实业务后做事:发送通知、记录日志等
        System.out.println("📧 【Alipay】已向客户发送转账成功通知");
        System.out.println("📝 【Alipay】本次交易日志已记录完毕\n");
        return result;
    }
}

第4步:启用管家并体验服务(客户端)

最后,我们来看看怎么使用这个管家

java 复制代码
import java.lang.reflect.Proxy;

public class Customer {
    public static void main(String[] args) {
        // 1. 找到真正的银行(创建真实对象)
        BankTransfer realBank = new RealBank();

        // 2. 为这家银行配一个Alipay管家,并给它工作手册
        AlipayInvocationHandler handbook = new AlipayInvocationHandler(realBank);

        // 3. 通过Proxy这个"管家生成器",生成一个代理银行的Alipay管家对象
        BankTransfer alipayProxy = (BankTransfer) Proxy.newProxyInstance(
                realBank.getClass().getClassLoader(), // 使用银行同款"知识库"
                new Class[]{BankTransfer.class},     // 告诉管家,它只代理BankTransfer这项业务
                handbook                             // 把工作手册交给管家
        );

        // 4. 客户直接和Alipay管家打交道,完全不用接触银行底层
        System.out.println("用户通过Alipay发起转账请求...");
        alipayProxy.transfer("张三", "李四", 5000.0);
        double balance = alipayProxy.queryAccountInfo("张三");
        System.out.println("查询结果: " + balance + "元");
    }
}

运行结果

当你运行程序,会看到如下输出,完美展示了代理的增强效果:

java 复制代码
用户通过Alipay发起转账请求...
✅ 【Alipay】身份验证通过
✅ 【Alipay】资金安全检查完成
🚀 【Alipay】开始执行核心转账业务...
[银行核心系统] 完成转账:张三 -> 李四, 金额:5000.0元
📧 【Alipay】已向客户发送转账成功通知
📝 【Alipay】本次交易日志已记录完毕

✅ 【Alipay】身份验证通过
✅ 【Alipay】资金安全检查完成
🚀 【Alipay】开始执行核心转账业务...
查询账户 张三 余额
📧 【Alipay】已向客户发送转账成功通知
📝 【Alipay】本次交易日志已记录完毕

查询结果: 10000.0元

进程已结束,退出代码0

💎 总结

概念 真实世界对应 在代码中的体现
真实对象 Bank(银行) RealBank类,只实现核心的 transfer方法
代理 Alipay(支付宝) 由 Proxy.newProxyInstance动态生成的对象
调用处理器 Alipay管家的工作手册 AlipayInvocationHandler类,在 invoke方法中添加验证、日志等
客户 使用支付宝的你 Customer类,它调用的是代理对象的方法

这样一来,​​动态代理​​ 就像一个超级业务管家,让你能在"神不知鬼不觉"的情况下,对核心业务进行功能增强。它最大的好处是​​解耦 ​​和​​灵活​​,银行代码(目标对象)完全不用修改,所有增强逻辑都由管家统一、动态地处理。

补充:

1. 在 Alipay 的动态代理中,要实现检测逻辑,核心是将其放置在 InvocationHandler的 invoke方法里。

在 Alipay 的动态代理中,要实现检测逻辑,核心是将其放置在 InvocationHandler的 invoke方法里。下面这个流程图清晰地展示了检测逻辑的完整执行顺序:

具体来说,你的检测函数可以根据其目的,放置在以下三个关键位置:

检测类型 放置位置 常见用途
前置检测 在 invoke方法内,调用 method.invoke(target, args) 之前 身份验证、权限校验、参数合法性检查、记录方法开始日志
后置检测 在 invoke方法内,调用 method.invoke(target, args) 之后,return结果之前 执行结果校验、记录方法结束日志、性能监控(计算耗时)
环绕检测 结合前置与后置检测,完整包裹目标方法的执行 事务管理、性能监控(记录开始和结束时间)

代码示例:在银行转账场景中加入检测

以下是如何在你熟悉的 AlipayInvocationHandler中具体添加检测逻辑的代码示例:

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class AlipayInvocationHandler implements InvocationHandler {
    private Object target; // 被代理的真实对象,例如Bank实例

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        // 1. 前置检测:在调用转账核心方法前进行
        System.out.println("【Alipay检测】开始身份验证与安全扫描...");
        // 模拟具体的检测逻辑,例如检查账户状态、转账金额是否合法等
        if (args != null && args.length > 2) {
            double amount = (Double) args[2];
            if (amount <= 0) {
                throw new IllegalArgumentException("转账金额必须大于零");
            }
        }
        System.out.println("【Alipay检测】前置检测通过");

        // 2. 执行核心业务方法(如Bank的transfer方法)
        Object result = method.invoke(target, args);

        // 3. 后置检测:在核心方法执行完毕后进行
        System.out.println("【Alipay检测】交易结果校验与日志记录...");
        // 这里可以检查交易是否成功、记录详细日志等
        System.out.println("【Alipay检测】后置检测完成,交易闭环");

        return result; // 返回核心业务方法的结果
    }
}

💎 核心要点总结

  • 核心位置:所有检测逻辑都应编写在实现了 InvocationHandler接口的类的 invoke方法中。
  • 灵活控制:你可以通过 method.getName()判断当前调用的是哪个方法,从而实现针对特定方法的检测。
  • 非侵入式:这种方式的巨大优势在于,无论是前置还是后置检测,都无需修改原始 Bank或 Alipay类的代码,实现了很好的解耦。

2. 基于银行取款接口和多个银行真实对象的场景代码演示:

基于银行取款接口和多个银行真实对象的场景,使用支付宝动态代理模式的实现方式如下:

核心架构设计

首先,我们定义核心接口和真实对象(银行A、银行B):

java 复制代码
// 1. 定义银行取款接口
public interface BankWithdrawal {
    double withdraw(String account, double amount);
    double getBalance(String account);
}

// 2. 实现真实银行对象 - 银行A
public class BankA implements BankWithdrawal {
    @Override
    public double withdraw(String account, double amount) {
        System.out.println("[银行A] 从账户 " + account + " 取款 " + amount + " 元");
        // 实际业务逻辑:更新账户余额等
        return amount;
    }
    
    @Override
    public double getBalance(String account) {
        System.out.println("[银行A] 查询账户 " + account + " 余额");
        return 10000.0; // 模拟余额
    }
}

// 3. 实现真实银行对象 - 银行B
public class BankB implements BankWithdrawal {
    @Override
    public double withdraw(String account, double amount) {
        System.out.println("[银行B] 从账户 " + account + " 取款 " + amount + " 元");
        // 实际业务逻辑:更新账户余额等
        return amount;
    }
    
    @Override
    public double getBalance(String account) {
        System.out.println("[银行B] 查询账户 " + account + " 余额");
        return 15000.0; // 模拟余额
    }
}

支付宝动态代理处理器

这是动态代理的核心,负责在银行核心业务前后添加支付宝的增强逻辑

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

public class AlipayInvocationHandler implements InvocationHandler {
    private Object target; // 被代理的银行对象
    
    public AlipayInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置处理:支付宝统一验证和风控
        System.out.println("🔐 【支付宝】身份验证和风险检测");
        System.out.println("📝 【支付宝】记录操作日志,方法: " + method.getName() + ", 参数: " + Arrays.toString(args));
        
        // 性能监控开始
        long startTime = System.currentTimeMillis();
        
        try {
            // 调用真实银行对象的核心方法[6](@ref)
            Object result = method.invoke(target, args);
            
            // 后置处理:成功逻辑
            System.out.println("✅ 【支付宝】操作成功完成");
            return result;
            
        } catch (Exception e) {
            // 异常处理
            System.out.println("❌ 【支付宝】操作失败: " + e.getMessage());
            throw e;
        } finally {
            // 最终处理:性能监控和资源清理
            long endTime = System.currentTimeMillis();
            System.out.println("⏱️ 【支付宝】操作耗时: " + (endTime - startTime) + "ms");
            System.out.println("---");
        }
    }
}

代理对象工厂

创建动态代理对象的工具类

java 复制代码
import java.lang.reflect.Proxy;

public class AlipayProxyFactory {
    public static BankWithdrawal createProxy(Object target) {
        // 创建并返回代理对象[6](@ref)
        return (BankWithdrawal) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new AlipayInvocationHandler(target)
        );
    }
}

客户端使用示例

java 复制代码
public class ClientDemo {
    public static void main(String[] args) {
        // 创建真实银行对象
        BankWithdrawal bankA = new BankA();
        BankWithdrawal bankB = new BankB();
        
        // 创建支付宝代理对象
        BankWithdrawal alipayProxyA = AlipayProxyFactory.createProxy(bankA);
        BankWithdrawal alipayProxyB = AlipayProxyFactory.createProxy(bankB);
        
        System.out.println("=== 支付宝代理银行A取款 ===");
        alipayProxyA.withdraw("张三001", 1000.0);
        alipayProxyA.getBalance("张三001");
        
        System.out.println("=== 支付宝代理银行B取款 ===");
        alipayProxyB.withdraw("李四002", 2000.0);
        alipayProxyB.getBalance("李四002");
        
        // 验证代理对象类型
        System.out.println("代理对象类型: " + alipayProxyA.getClass());
        System.out.println("是否是代理对象: " + Proxy.isProxyClass(alipayProxyA.getClass()));
    }
}

运行结果展示

java 复制代码
=== 支付宝代理银行A取款 ===
🔐 【支付宝】身份验证和风险检测
📝 【支付宝】记录操作日志,方法: withdraw, 参数: [张三001, 1000.0]
[银行A] 从账户 张三001 取款 1000.0 元
✅ 【支付宝】操作成功完成
⏱️ 【支付宝】操作耗时: 5ms
---
🔐 【支付宝】身份验证和风险检测
📝 【支付宝】记录操作日志,方法: getBalance, 参数: [张三001]
[银行A] 查询账户 张三001 余额
✅ 【支付宝】操作成功完成
⏱️ 【支付宝】操作耗时: 2ms
---

动态代理的优势

这种设计带来了以下重要优势

​​* 通用性强​​:一个AlipayInvocationHandler可以代理任何实现了BankWithdrawal接口的银行对象

  • 解耦彻底:支付宝的增强逻辑(验证、日志、监控)与银行业务逻辑完全分离
    * 维护方便:新增银行或修改增强逻辑时,无需改动现有代码
    * 灵活扩展:可以轻松添加新的银行或新的横切关注点

进阶优化建议

如果需要更精细的控制,可以在invoke方法中根据具体方法进行差异化处理:

java 复制代码
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 针对不同方法进行特殊处理
    if ("withdraw".equals(method.getName())) {
        System.out.println("💰 【支付宝】大额取款风控检测");
        // 大额取款特殊风控逻辑
        if (args.length > 1 && (Double)args[1] > 50000) {
            System.out.println("⚠️ 【支付宝】大额取款需要二次验证");
        }
    }
    
    // ... 其余通用逻辑
}

这种动态代理模式完美模拟了支付宝作为第三方支付平台代理多家银行业务的真实场景,既保证了各银行核心业务的独立性,又通过支付宝提供了统一的增值服务。

3. 基于支付宝和微信两种方式动态代理单个银行A的取款接口

系统架构设计

首先,我们定义核心的银行取款接口和实现类:

java 复制代码
// 1. 定义银行取款接口
public interface BankWithdrawal {
    boolean withdraw(String account, double amount);
    double queryBalance(String account);
}

// 2. 真实银行对象 - 银行A
public class BankA implements BankWithdrawal {
    @Override
    public boolean withdraw(String account, double amount) {
        System.out.println("[银行A核心系统] 从账户 " + account + " 取款 " + amount + " 元");
        // 实际的扣款逻辑
        return true;
    }
    
    @Override
    public double queryBalance(String account) {
        System.out.println("[银行A核心系统] 查询账户 " + account + " 余额");
        return 10000.0; // 模拟余额
    }
}

支付宝动态代理处理器

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class AlipayInvocationHandler implements InvocationHandler {
    private Object target; // 被代理的银行对象
    
    public AlipayInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 支付宝特有的前置处理
        System.out.println("🔐 【支付宝】蚂蚁盾安全验证");
        System.out.println("📱 【支付宝】生物识别验证");
        
        // 支付宝特有的风控逻辑
        if ("withdraw".equals(method.getName()) && args != null && args.length > 1) {
            double amount = (Double) args[1];
            if (amount > 5000) {
                System.out.println("⚠️ 【支付宝】大额取款需要短信验证");
            }
        }
        
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long endTime = System.currentTimeMillis();
        
        // 支付宝特有的后置处理
        System.out.println("🌺 【支付宝】赠送蚂蚁森林能量");
        System.out.println("💎 【支付宝】更新芝麻信用记录");
        System.out.println("⏱️ 【支付宝】本次交易耗时: " + (endTime - startTime) + "ms");
        
        return result;
    }
}

微信支付动态代理处理器

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class WechatPayInvocationHandler implements InvocationHandler {
    private Object target; // 被代理的银行对象
    
    public WechatPayInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 微信支付特有的前置处理
        System.out.println("🔐 【微信支付】微信安全中心验证");
        System.out.println("💬 【微信支付】检测微信登录状态");
        
        // 微信支付特有的社交化功能
        if ("withdraw".equals(method.getName())) {
            System.out.println("👥 【微信支付】可分享交易到朋友圈");
        }
        
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long endTime = System.currentTimeMillis();
        
        // 微信支付特有的后置处理
        System.out.println("🧧 【微信支付】发放微信支付优惠券");
        System.out.println("📱 【微信支付】发送微信支付通知");
        System.out.println("⏱️ 【微信支付】本次交易耗时: " + (endTime - startTime) + "ms");
        
        return result;
    }
}

统一的代理工厂

java 复制代码
import java.lang.reflect.Proxy;

public class PaymentProxyFactory {
    /**
     * 创建支付宝代理
     */
    public static BankWithdrawal createAlipayProxy(BankWithdrawal target) {
        return (BankWithdrawal) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new AlipayInvocationHandler(target)
        );
    }
    
    /**
     * 创建微信支付代理
     */
    public static BankWithdrawal createWechatPayProxy(BankWithdrawal target) {
        return (BankWithdrawal) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new WechatPayInvocationHandler(target)
        );
    }
}

客户端测试示例

java 复制代码
public class PaymentClient {
    public static void main(String[] args) {
        // 创建真实的银行对象
        BankWithdrawal bankA = new BankA();
        
        // 创建不同的支付代理
        BankWithdrawal alipayProxy = PaymentProxyFactory.createAlipayProxy(bankA);
        BankWithdrawal wechatPayProxy = PaymentProxyFactory.createWechatPayProxy(bankA);
        
        System.out.println("======= 支付宝代理取款 =======");
        alipayProxy.withdraw("张三001", 2000.0);
        alipayProxy.queryBalance("张三001");
        
        System.out.println("\n======= 微信支付代理取款 =======");
        wechatPayProxy.withdraw("李四002", 3000.0);
        wechatPayProxy.queryBalance("李四002");
        
        // 验证代理对象类型
        System.out.println("\n======= 代理类型验证 =======");
        System.out.println("支付宝代理类型: " + alipayProxy.getClass());
        System.out.println("微信代理类型: " + wechatPayProxy.getClass());
        System.out.println("是否都是代理: " + 
            java.lang.reflect.Proxy.isProxyClass(alipayProxy.getClass()) + ", " +
            java.lang.reflect.Proxy.isProxyClass(wechatPayProxy.getClass()));
    }
}

运行结果展示

java 复制代码
======= 支付宝代理取款 =======
🔐 【支付宝】蚂蚁盾安全验证
📱 【支付宝】生物识别验证
[银行A核心系统] 从账户 张三001 取款 2000.0 元
🌺 【支付宝】赠送蚂蚁森林能量
💎 【支付宝】更新芝麻信用记录
⏱️ 【支付宝】本次交易耗时: 3ms

======= 微信支付代理取款 =======
🔐 【微信支付】微信安全中心验证
💬 【微信支付】检测微信登录状态
👥 【微信支付】可分享交易到朋友圈
[银行A核心系统] 从账户 李四002 取款 3000.0 元
🧧 【微信支付】发放微信支付优惠券
📱 【微信支付】发送微信支付通知
⏱️ 【微信支付】本次交易耗时: 2ms

设计优势分析

  1. 平台差异化服务
    支付宝代理:侧重安全验证和信用体系,提供蚂蚁森林等生态服务
    微信支付代理:侧重社交功能和即时通知,利用微信生态优势
  2. 代码复用与解耦
    同一个银行核心(BankA)被不同代理增强,业务逻辑完全分离
    新增支付平台只需实现新的InvocationHandler,符合开闭原则
  3. 动态代理的核心价值
    与静态代理相比,动态代理的优势在于

    一个处理器可代理多个方法,避免为每个方法编写重复代码
    运行时动态生成代理类,更加灵活
    易于扩展和维护,新增功能只需修改处理器

实际应用场景扩展

这种模式在实际支付系统中的典型应用:

java 复制代码
// 在实际系统中,可以根据用户选择动态切换代理
public class PaymentService {
    private BankWithdrawal currentProxy;
    
    public void setPaymentPlatform(String platform, BankWithdrawal bank) {
        switch (platform.toLowerCase()) {
            case "alipay":
                this.currentProxy = PaymentProxyFactory.createAlipayProxy(bank);
                break;
            case "wechat":
                this.currentProxy = PaymentProxyFactory.createWechatPayProxy(bank);
                break;
            default:
                throw new IllegalArgumentException("不支持的支付平台");
        }
    }
    
    public boolean processWithdrawal(String account, double amount) {
        return currentProxy.withdraw(account, amount);
    }
}

这种设计模式让支付平台可以灵活切换,同时保持银行核心业务的稳定性,是现代支付系统架构的常见实践

相关推荐
简小瑞2 小时前
VSCode用它管理上千个服务:依赖注入从入门到实战
前端·设计模式
开心-开心急了2 小时前
PySide6 文本编辑器(QPlainTextEdit)实现查找功能——重构版本
开发语言·python·ui·重构·pyqt
郝学胜-神的一滴2 小时前
Effective Python 第39条:通过@classmethod多态来构造同一体系中的各类对象
开发语言·python·程序人生·软件工程
聪明的笨猪猪3 小时前
Java “并发工具类”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
whltaoin3 小时前
Spring Boot 常用注解分类整理(含用法示例)
java·spring boot·后端·注解·开发技巧
IT森林里的程序猿3 小时前
基于Python的招聘信息可视化分析系统
开发语言·python
charlie1145141913 小时前
精读C++20设计模式——结构型设计模式:外观模式
c++·学习·设计模式·c++20·外观模式
卷Java4 小时前
用户权限控制功能实现说明
java·服务器·开发语言·数据库·servlet·微信小程序·uni-app
从零开始学习人工智能4 小时前
Spring Security 实战:彻底解决 CORS 跨域凭据问题与 WebSocket 连接失败
java·websocket·spring