8、Java 代理模式从入门到实战

Java 代理模式从入门到实战(后端必看,附案例+面试考点)

前言:代理模式是Java设计模式中最常用的模式之一,也是Spring AOP、MyBatis插件等框架的核心底层原理。很多Java开发者每天都在间接使用代理模式,却对其底层实现一知半解;新手面对"静态代理、动态代理、CGLIB代理"容易混淆,面试时被问到"Spring AOP用了什么代理方式""JDK代理和CGLIB代理的区别"就卡壳。本文从入门到实战,用极简语言拆解代理模式核心,结合可直接复制运行的代码案例、真实业务场景(日志增强、权限控制),以及高频面试考点,带你吃透代理模式,新手也能快速上手,看完就能落地到项目中。

一、为什么Java后端必须掌握代理模式?(痛点直击)

先看3个Java后端开发中最常见的场景,你一定遇到过:

  • 场景1:给核心业务方法添加日志、事务、权限控制,不想修改原有业务代码(遵循"开闭原则");

  • 场景2:调用第三方接口(如支付、短信),需要统一处理异常、重试、超时控制,避免重复编码;

  • 场景3:面试时,面试官追问"Spring AOP的底层实现""动态代理的原理",无法清晰阐述,印象分大打折扣。

而代理模式的核心价值,就是在不修改目标对象代码的前提下,对目标对象的方法进行增强(新增功能),实现"业务逻辑"与"增强逻辑"的解耦,这也是它成为框架核心的关键原因。

核心结论:代理模式不是"花里胡哨"的设计,而是后端开发的"实用工具"------初级开发者用它解耦代码,中级开发者用它封装通用逻辑,高级开发者用它理解框架底层,面试时更是高频考点。

二、代理模式核心概念(极简入门,无需死记硬背)

代理模式的本质很简单:找一个"代理类",代替"目标类"执行方法,在执行前后添加增强逻辑。就像生活中"中介"------你(目标类)想租房,不用自己找房源、谈价格,中介(代理类)帮你完成,还能帮你审核房源(增强逻辑),你只需要专注于"租房"本身。

核心角色(3个,必记):

  1. 目标对象(Target):被代理的对象,核心业务逻辑的实现者(比如"租房的你");

  2. 代理对象(Proxy):代替目标对象执行方法,添加增强逻辑(比如"中介");

  3. 抽象主题(Subject):目标对象和代理对象共同实现的接口(或继承的类),定义核心方法(比如"租房接口",规定租房的核心操作)。

核心原则:代理对象与目标对象"功能一致"(实现同一接口/继承同一类),代理对象持有目标对象的引用,在调用目标方法时嵌入增强逻辑。

代理模式分类(3种,重点掌握后两种):静态代理、JDK动态代理、CGLIB动态代理,其中JDK动态代理是Java原生支持,CGLIB是第三方框架支持,两者在Spring中都有广泛应用。

三、三种代理模式详解(附可复制代码,新手必练)

以"用户登录业务"为案例,给登录方法添加"日志增强"(记录方法调用时间、参数),分别用三种代理方式实现,对比差异,一看就懂。

3.1 静态代理(基础,入门必学)

【含义】:代理类是手动编写的(编译期就存在),与目标类实现同一接口,持有目标对象的引用,手动添加增强逻辑。

【实现步骤】:1. 定义抽象主题(接口);2. 实现目标类(核心业务);3. 实现代理类(持有目标对象,添加增强逻辑);4. 测试调用。

【代码实现】(可直接复制运行):

java 复制代码
// 1. 抽象主题(接口):定义核心业务方法
public interface UserService {
    // 核心业务:用户登录
    boolean login(String username, String password);
}

// 2. 目标对象(核心业务实现)
public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        // 核心业务逻辑(模拟登录校验)
        System.out.println("执行核心登录逻辑:校验用户名密码");
        return "admin".equals(username) && "123456".equals(password);
    }
}

// 3. 代理对象(静态代理类):添加日志增强
public class UserServiceStaticProxy implements UserService {
    // 持有目标对象的引用
    private final UserService target;

    // 构造方法注入目标对象
    public UserServiceStaticProxy(UserService target) {
        this.target = target;
    }

    @Override
    public boolean login(String username, String password) {
        // 增强逻辑:方法执行前(记录日志)
        System.out.println("日志增强:登录方法开始调用,参数:username=" + username + ", password=" + password);
        long startTime = System.currentTimeMillis();

        // 调用目标对象的核心方法
        boolean result = target.login(username, password);

        // 增强逻辑:方法执行后(记录耗时)
        long endTime = System.currentTimeMillis();
        System.out.println("日志增强:登录方法调用结束,耗时:" + (endTime - startTime) + "ms,结果:" + result);

        return result;
    }
}

// 4. 测试类
public class StaticProxyTest {
    public static void main(String[] args) {
        // 1. 创建目标对象
        UserService target = new UserServiceImpl();
        // 2. 创建代理对象,注入目标对象
        UserService proxy = new UserServiceStaticProxy(target);
        // 3. 调用代理对象的方法(间接调用目标方法,触发增强逻辑)
        proxy.login("admin", "123456");
    }
}

【运行结果】:

text 复制代码
日志增强:登录方法开始调用,参数:username=admin, password=123456
执行核心登录逻辑:校验用户名密码
日志增强:登录方法调用结束,耗时:1ms,结果:true

【优点】:简单易懂,手动控制增强逻辑,无额外依赖;

【缺点】:代码冗余------每一个目标类都需要对应一个代理类,若目标类增多、方法修改,代理类也需同步修改,维护成本高(不符合"开闭原则")。

【适用场景】:简单场景、目标类少、增强逻辑固定(如单一接口的简单增强)。

3.2 JDK动态代理(重点,Java原生,面试高频)

【含义】:代理类是运行时动态生成 的(编译期不存在),无需手动编写代理类,依赖Java原生的java.lang.reflect.Proxy类和InvocationHandler接口,要求目标类必须实现接口

【核心原理】:通过Proxy.newProxyInstance()方法,在运行时动态生成代理类,将增强逻辑封装在InvocationHandler的invoke()方法中,调用代理方法时,会自动触发invoke()方法。

【核心API说明】:

  • Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):生成代理对象;

    • loader:目标对象的类加载器;

    • interfaces:目标对象实现的所有接口;

    • h:InvocationHandler接口实现类(封装增强逻辑)。

  • InvocationHandler.invoke(Object proxy, Method method, Object[] args):代理方法的核心执行逻辑;

    • proxy:生成的代理对象;

    • method:当前调用的目标方法;

    • args:当前调用方法的参数;

    • return:目标方法的返回值。

【代码实现】(可直接复制运行):

java 复制代码
// 1. 抽象主题(接口):和静态代理一致(可复用)
public interface UserService {
    boolean login(String username, String password);
}

// 2. 目标对象(核心业务实现):和静态代理一致(可复用)
public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        System.out.println("执行核心登录逻辑:校验用户名密码");
        return "admin".equals(username) && "123456".equals(password);
    }
}

// 3. 增强逻辑处理器:实现InvocationHandler接口
public class LogInvocationHandler implements InvocationHandler {
    // 持有目标对象的引用
    private final Object target;

    // 构造方法注入目标对象(通用,可复用,无需针对单个目标类修改)
    public LogInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 代理方法的核心逻辑:所有代理对象的方法调用,都会触发此方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 增强逻辑:方法执行前(记录日志)
        System.out.println("JDK动态代理-日志增强:方法开始调用,方法名:" + method.getName() + ",参数:" + Arrays.toString(args));
        long startTime = System.currentTimeMillis();

        // 调用目标对象的核心方法(反射调用)
        Object result = method.invoke(target, args);

        // 增强逻辑:方法执行后(记录耗时)
        long endTime = System.currentTimeMillis();
        System.out.println("JDK动态代理-日志增强:方法调用结束,耗时:" + (endTime - startTime) + "ms,结果:" + result);

        return result;
    }
}

// 4. 测试类
public class JdkDynamicProxyTest {
    public static void main(String[] args) {
        // 1. 创建目标对象
        UserService target = new UserServiceImpl();
        // 2. 创建增强逻辑处理器,注入目标对象
        InvocationHandler handler = new LogInvocationHandler(target);
        // 3. 动态生成代理对象(核心代码)
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标对象类加载器
                target.getClass().getInterfaces(),  // 目标对象实现的接口
                handler                             // 增强逻辑处理器
        );
        // 4. 调用代理对象的方法
        proxy.login("admin", "123456");
    }
}

【运行结果】:和静态代理一致,但无需手动编写代理类;

【优点】:无需手动编写代理类,一个增强处理器可复用(适配所有实现接口的目标类),减少代码冗余,符合"开闭原则";

【缺点】:目标类必须实现接口,若目标类没有实现任何接口,无法使用JDK动态代理;

【适用场景】:目标类实现接口的场景(Java后端大部分场景,如Service层接口),也是Spring AOP默认使用的代理方式(目标类有接口时)。

3.3 CGLIB动态代理(重点,无接口场景,面试高频)

【含义】:代理类是运行时动态生成 的,依赖第三方框架CGLIB(Code Generation Library),无需目标类实现接口,通过"继承目标类"的方式生成代理类(代理类是目标类的子类)。

【核心原理】:CGLIB通过ASM字节码技术,在运行时动态生成目标类的子类,重写目标类的方法,在重写方法中嵌入增强逻辑;由于是继承,目标类不能是final类(final类不能被继承),目标方法也不能是final方法(final方法不能被重写)。

【依赖说明】:Spring框架已集成CGLIB,若项目中引入Spring-core,无需额外导入依赖;若单独使用,需导入以下依赖(Maven):

xml 复制代码
<!-- CGLIB依赖 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

【核心API说明】:

  • Enhancer:CGLIB的核心类,用于生成代理对象;

  • MethodInterceptor:方法拦截器接口,封装增强逻辑,重写intercept()方法(类似JDK动态代理的InvocationHandler.invoke())。

【代码实现】(可直接复制运行):

java 复制代码
// 1. 目标对象(无接口,直接是普通类)
public class UserService {
    // 核心业务:用户登录(无接口实现)
    public boolean login(String username, String password) {
        System.out.println("执行核心登录逻辑:校验用户名密码");
        return "admin".equals(username) && "123456".equals(password);
    }
}

// 2. 方法拦截器:实现MethodInterceptor接口,封装增强逻辑
public class LogMethodInterceptor implements MethodInterceptor {
    /**
     * 拦截目标方法,添加增强逻辑
     * @param o 代理对象(目标类的子类)
     * @param method 目标方法
     * @param args 方法参数
     * @param methodProxy 方法代理对象(用于调用目标方法)
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 增强逻辑:方法执行前(记录日志)
        System.out.println("CGLIB动态代理-日志增强:方法开始调用,方法名:" + method.getName() + ",参数:" + Arrays.toString(args));
        long startTime = System.currentTimeMillis();

        // 调用目标对象的核心方法(两种方式,推荐第二种,效率更高)
        // 方式1:通过反射调用目标方法
        // Object result = method.invoke(target, args);
        // 方式2:通过方法代理调用目标方法(CGLIB推荐,避免反射开销)
        Object result = methodProxy.invokeSuper(o, args);

        // 增强逻辑:方法执行后(记录耗时)
        long endTime = System.currentTimeMillis();
        System.out.println("CGLIB动态代理-日志增强:方法调用结束,耗时:" + (endTime - startTime) + "ms,结果:" + result);

        return result;
    }
}

// 3. 测试类
public class CglibDynamicProxyTest {
    public static void main(String[] args) {
        // 1. 创建CGLIB核心增强器
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类(目标类):代理类继承目标类
        enhancer.setSuperclass(UserService.class);
        // 3. 设置方法拦截器(增强逻辑)
        enhancer.setCallback(new LogMethodInterceptor());
        // 4. 动态生成代理对象(核心代码)
        UserService proxy = (UserService) enhancer.create();
        // 5. 调用代理对象的方法
        proxy.login("admin", "123456");
    }
}

【运行结果】:和前两种代理一致,支持无接口的目标类;

【优点】:无需目标类实现接口,适用范围更广;底层是字节码增强,执行效率比JDK动态代理(反射)略高;

【缺点】:依赖第三方框架;目标类不能是final类,目标方法不能是final方法;字节码增强的逻辑比JDK动态代理更复杂;

【适用场景】:目标类没有实现接口的场景(如遗留系统的类),也是Spring AOP的备用代理方式(目标类无接口时)。

三种代理模式对比(表格总结,一目了然,面试必背)

代理类型 核心特点 目标类要求 依赖 执行效率 适用场景
静态代理 手动编写代理类,增强逻辑固定 需实现接口(或继承类) 无(原生Java) 最高(无反射/字节码开销) 简单场景、目标类少
JDK动态代理 运行时动态生成代理类,增强逻辑可复用 必须实现接口 无(原生Java) 中等(反射开销) 目标类有接口(主流场景)
CGLIB动态代理 运行时动态生成子类,增强逻辑可复用 无接口要求,不能是final类 CGLIB框架(Spring已集成) 较高(字节码增强,无反射开销) 目标类无接口、遗留系统

四、代理模式实战(真实业务场景,可直接复用)

结合Java后端最常见的"接口增强"场景,用代理模式实现"日志记录+权限控制+异常处理"的通用增强,贴合真实项目开发,代码可直接复制到项目中使用。

4.1 实战场景说明

场景:用户中心Service层,有登录、注册、注销三个核心方法,需要给所有方法添加以下增强逻辑(解耦,不修改原有Service代码):

  1. 日志记录:记录方法调用时间、参数、返回值、耗时;

  2. 权限控制:只有管理员才能调用注销方法;

  3. 异常处理:统一捕获方法调用中的异常,记录异常信息,避免程序崩溃。

4.2 实战代码实现(JDK动态代理,主流选择)

java 复制代码
// 1. 抽象主题(Service接口)
public interface UserService {
    // 登录
    boolean login(String username, String password);
    // 注册
    boolean register(String username, String password);
    // 注销(需要管理员权限)
    boolean logout(Long userId);
}

// 2. 目标对象(Service实现类,核心业务)
public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        // 模拟登录逻辑
        System.out.println("执行登录逻辑:username=" + username);
        return "admin".equals(username) && "123456".equals(password);
    }

    @Override
    public boolean register(String username, String password) {
        // 模拟注册逻辑
        System.out.println("执行注册逻辑:username=" + username);
        return true;
    }

    @Override
    public boolean logout(Long userId) {
        // 模拟注销逻辑
        System.out.println("执行注销逻辑:userId=" + userId);
        return true;
    }
}

// 3. 通用增强处理器(集成日志、权限、异常处理)
public class CommonInvocationHandler implements InvocationHandler {
    // 目标对象
    private final Object target;
    // 模拟当前登录用户(实际项目中从ThreadLocal获取)
    private final String currentUser = "admin";

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // 增强1:日志记录(方法执行前)
            System.out.println("【日志增强】方法开始调用:" + method.getName() + ",参数:" + Arrays.toString(args) + ",调用时间:" + new Date());

            // 增强2:权限控制(只对logout方法生效)
            if ("logout".equals(method.getName())) {
                if (!"admin".equals(currentUser)) {
                    System.out.println("【权限增强】当前用户无管理员权限,禁止调用注销方法");
                    return false;
                }
            }

            // 调用目标方法(核心业务)
            Object result = method.invoke(target, args);

            // 增强1:日志记录(方法执行后)
            System.out.println("【日志增强】方法调用成功:" + method.getName() + ",返回值:" + result);
            return result;
        } catch (Exception e) {
            // 增强3:异常处理
            System.out.println("【异常增强】方法调用异常:" + method.getName() + ",异常信息:" + e.getMessage());
            // 可根据需求抛出异常或返回默认值
            return false;
        }
    }
}

// 4. 代理工厂(封装代理对象生成逻辑,可复用)
public class ProxyFactory {
    // 私有化构造方法,禁止实例化
    private ProxyFactory() {}

    /**
     * 生成JDK动态代理对象
     * @param target 目标对象
     * @return 代理对象
     */
    public static Object getJdkProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new CommonInvocationHandler(target)
        );
    }
}

// 5. 测试类(模拟真实项目调用)
public class ProxyPracticeTest {
    public static void main(String[] args) {
        // 1. 创建目标对象
        UserService target = new UserServiceImpl();
        // 2. 通过代理工厂获取代理对象
        UserService proxy = (UserService) ProxyFactory.getJdkProxy(target);

        // 测试1:调用登录方法(无权限控制)
        System.out.println("=== 测试登录 ===");
        proxy.login("admin", "123456");

        // 测试2:调用注册方法(无权限控制)
        System.out.println("\n=== 测试注册 ===");
        proxy.register("test", "123456");

        // 测试3:调用注销方法(有管理员权限)
        System.out.println("\n=== 测试注销(管理员) ===");
        proxy.logout(1L);

        // 测试4:模拟非管理员调用注销方法(修改currentUser为普通用户)
        // (实际项目中可通过修改ThreadLocal中的用户信息测试)
    }
}

【运行结果】:

text 复制代码
=== 测试登录 ===
【日志增强】方法开始调用:login,参数:[admin, 123456],调用时间:Wed Apr 15 23:00:00 CST 2026
执行登录逻辑:username=admin
【日志增强】方法调用成功:login,返回值:true

=== 测试注册 ===
【日志增强】方法开始调用:register,参数:[test, 123456],调用时间:Wed Apr 15 23:00:00 CST 2026
执行注册逻辑:username=test
【日志增强】方法调用成功:register,返回值:true

=== 测试注销(管理员) ===
【日志增强】方法开始调用:logout,参数:[1],调用时间:Wed Apr 15 23:00:00 CST 2026
【权限增强】当前用户有管理员权限,允许调用注销方法
执行注销逻辑:userId=1
【日志增强】方法调用成功:logout,返回值:true

【实战亮点】:

  • 解耦:业务逻辑(UserServiceImpl)与增强逻辑(CommonInvocationHandler)完全分离,修改增强逻辑无需改动业务代码;

  • 复用:增强处理器和代理工厂可复用,适配所有实现接口的Service类;

  • 可扩展:新增增强逻辑(如事务控制、缓存),只需修改增强处理器,符合"开闭原则"。

五、代理模式在框架中的应用(面试必提)

代理模式的核心价值是"解耦+增强",这也是它被广泛应用在主流框架中的原因,掌握这些应用场景,面试时能加分不少。

5.1 Spring AOP(核心应用)

Spring AOP(面向切面编程)的底层就是基于代理模式实现的,核心逻辑:

  • 当目标类实现接口 时,Spring AOP默认使用JDK动态代理

  • 当目标类没有实现接口 时,Spring AOP会使用CGLIB动态代理

  • 我们定义的切面(@Aspect)、通知(@Before、@After、@Around),本质就是代理模式的"增强逻辑",Spring会自动生成代理对象,将切面逻辑嵌入到目标方法中。

示例:Spring AOP的日志切面,本质就是动态代理的增强逻辑,和我们实战中的日志增强完全一致。

5.2 MyBatis(插件机制)

MyBatis的插件机制(如分页插件、日志插件),底层使用JDK动态代理,对MyBatis的核心接口(Executor、StatementHandler等)进行代理,在执行SQL的前后添加增强逻辑(如分页处理、SQL日志记录)。

5.3 Spring Security(权限控制)

Spring Security的权限控制,通过动态代理对Controller、Service层的方法进行拦截,判断当前用户是否有对应权限,本质就是代理模式的"权限增强"逻辑(和我们实战中的权限控制一致)。

六、代理模式面试高频考点(必背,避坑)

代理模式是Java后端面试的高频考点,尤其是中级及以上岗位,重点考察"动态代理原理"和"框架应用",记住以下考点,轻松应对面试。

1. JDK动态代理和CGLIB动态代理的区别?(高频中的高频)

核心区别(一句话记住,面试直接说):

  • 底层实现:JDK动态代理基于接口(反射),CGLIB基于继承(字节码增强);

  • 目标类要求:JDK要求目标类实现接口,CGLIB要求目标类不能是final类;

  • 执行效率:CGLIB(字节码增强)比JDK(反射)略高;

  • 依赖:JDK原生支持,CGLIB依赖第三方框架(Spring已集成)。

2. Spring AOP用了哪种代理模式?怎么选择?

核心答案:Spring AOP默认使用JDK动态代理,当目标类没有实现接口时,自动切换为CGLIB动态代理;也可以通过配置强制使用CGLIB代理。

补充:Spring Boot 2.x版本后,默认使用CGLIB代理(因为大部分场景下,CGLIB的执行效率更高,且无需目标类实现接口)。

3. 静态代理的缺点是什么?为什么要用动态代理?

  • 静态代理缺点:代码冗余,每一个目标类都需要对应一个代理类,维护成本高,不符合"开闭原则";

  • 动态代理优势:无需手动编写代理类,增强逻辑可复用,减少代码冗余,支持动态扩展,符合"开闭原则"。

4. CGLIB为什么不能代理final类和final方法?

核心原因:CGLIB是通过"继承目标类"生成代理类,重写目标方法来实现增强;而final类不能被继承,final方法不能被重写,因此CGLIB无法对其进行代理。

5. 代理模式的核心作用是什么?应用场景有哪些?

  • 核心作用:在不修改目标对象代码的前提下,对目标方法进行增强,实现"业务逻辑"与"增强逻辑"的解耦;

  • 应用场景:日志记录、权限控制、异常处理、事务控制、缓存、第三方接口增强(重试、超时)等。

七、总结(实战+面试双达标)

代理模式不难,核心是"解耦+增强",无需死记硬背,结合代码案例和框架应用理解,多练几次就能熟练掌握。对于Java后端开发者来说,代理模式不仅是设计模式的知识点,更是理解框架底层、编写高质量代码的基础。

  1. 基础:掌握3种代理模式的核心实现,重点区分静态代理与动态代理的差异;

  2. 核心:吃透JDK动态代理和CGLIB代理的区别(面试高频),理解两者的适用场景;

  3. 实战:结合真实业务场景,实现通用的增强逻辑(日志、权限、异常),可直接复用在项目中;

  4. 面试:记住高频考点,结合Spring AOP等框架的应用,清晰阐述代理模式的底层原理。

记住一句话:代理模式的核心不是"代理",而是"无侵入增强"------在不破坏原有代码逻辑的前提下,新增功能,这也是它能成为框架核心底层的关键。掌握它,不仅能让你的代码更优雅、更易维护,还能在面试中脱颖而出,成为"懂原理、能落地"的后端开发者。

补充:常见问题解决(避坑指南)

  • 问题1:JDK动态代理报错"ClassCastException"?

    解决:确保代理对象强转的类型是目标类实现的接口,而不是目标类本身(JDK代理生成的代理类只实现接口,不继承目标类);

  • 问题2:CGLIB代理报错"Cannot subclass final class"?

    解决:修改目标类,去掉final修饰符;若目标类不能修改,改用JDK动态代理(给目标类添加接口);

  • 问题3:Spring AOP切面不生效?

    解决:检查目标类是否实现接口(无接口时确保Spring配置了CGLIB代理),切面注解(@Aspect、@Component)是否正确,通知表达式是否匹配目标方法。

相关推荐
人道领域2 小时前
【黑马点评日记02】Redis解决Tomcat集群Session共享问题
java·前端·后端·架构·tomcat·firefox
cheems95272 小时前
[JavaEE]深度解构 Spring 核心:从控制反转 (IoC) 到依赖注入 (DI) 的架构演进
java·spring·架构·java-ee
毅炼2 小时前
MySQL常见问题总结(2)
java·数据库·mysql
庞轩px2 小时前
第二篇:String、StringBuilder、StringBuffer深度剖析
java·字符串·stringbuilder·string·stringbuffer·字符串常量池
色空大师2 小时前
【阿里云部署服务问题指南】
java·mysql·阿里云·docker
Rsun045512 小时前
9、Java 外观模式从入门到实战
java·开发语言·外观模式
清心歌2 小时前
TreeSet 深度解析
java·开发语言
迷藏4942 小时前
**RISC-V生态下的嵌入式开发新范式:从指令集到自定义外设的全流程实战**在当前国产化
java·python·risc-v
小松加哲2 小时前
Tomcat 核心原理全解析(含请求流转+组件源码+多应用配置)
java·tomcat·firefox