导读:本期聚焦于小伙伴创作的《怎么通过代理模式为目标对象的方法调用增加前置权限校验》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《怎么通过代理模式为目标对象的方法调用增加前置权限校验》有用,将其分享出去将是对创作者最好的鼓励。

代理模式的核心是通过一个代理对象来包装目标对象,客户端调用代理对象的方法时,代理对象可以在调用目标对象对应方法前后插入自定义逻辑,从而实现功能增强。要在目标对象的方法调用前增加前置权限校验,只需要把校验逻辑放在代理对象调用目标方法之前即可。

怎么通过代理模式为目标对象的方法调用增加前置权限校验

静态代理实现方式

静态代理需要手动创建代理类,代理类实现和目标对象相同的接口,内部持有目标对象的引用,在接口方法中先执行权限校验,再调用目标对象的方法。

定义业务接口

首先定义一个用户服务的业务接口,包含查询用户信息的方法:

// 用户服务接口
public interface UserService {
    String getUserInfo(String userId);
}

实现目标对象

创建接口的实现类,也就是我们的目标对象,内部只实现核心业务逻辑:

// 目标用户服务实现类
public class UserServiceImpl implements UserService {
    @Override
    public String getUserInfo(String userId) {
        return "用户ID:" + userId + ",用户信息:张三";
    }
}

创建静态代理类

代理类同样实现UserService接口,构造方法接收目标对象作为参数,在getUserInfo方法内先执行权限校验,再调用目标对象的方法:

// 静态代理类
public class UserStaticProxy implements UserService {
    // 持有目标对象的引用
    private UserService targetUserService;

    public UserStaticProxy(UserService targetUserService) {
        this.targetUserService = targetUserService;
    }

    @Override
    public String getUserInfo(String userId) {
        // 前置权限校验逻辑
        if (!checkPermission(userId)) {
            throw new RuntimeException("当前用户无权限查询该用户信息");
        }
        // 校验通过,调用目标对象的方法
        return targetUserService.getUserInfo(userId);
    }

    // 权限校验方法
    private boolean checkPermission(String userId) {
        // 这里模拟权限校验规则,实际可以对接权限系统
        return "admin".equals(userId) || "1001".equals(userId);
    }
}

静态代理测试

编写测试代码验证静态代理的效果:

public class StaticProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService targetService = new UserServiceImpl();
        // 创建静态代理对象
        UserService proxyService = new UserStaticProxy(targetService);

        // 有权限的用户调用
        try {
            String result1 = proxyService.getUserInfo("1001");
            System.out.println("调用结果:" + result1);
        } catch (Exception e) {
            System.out.println("调用失败:" + e.getMessage());
        }

        // 无权限的用户调用
        try {
            String result2 = proxyService.getUserInfo("1002");
            System.out.println("调用结果:" + result2);
        } catch (Exception e) {
            System.out.println("调用失败:" + e.getMessage());
        }
    }
}

动态代理实现方式

静态代理需要为每个目标类手动编写代理类,当业务接口较多时会产生大量冗余代码。动态代理可以在运行时动态生成代理对象,不需要手动编写代理类,更适合复杂场景。

JDK动态代理实现

JDK动态代理要求目标对象必须实现接口,通过InvocationHandler接口实现方法调用拦截,在调用目标方法前插入权限校验逻辑:

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

// JDK动态代理处理器
public class PermissionInvocationHandler implements InvocationHandler {
    // 目标对象
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 只拦截getUserInfo方法,其他方法直接放行
        if ("getUserInfo".equals(method.getName()) && args != null && args.length == 1) {
            String userId = (String) args[0];
            // 前置权限校验
            if (!checkPermission(userId)) {
                throw new RuntimeException("当前用户无权限查询该用户信息");
            }
        }
        // 调用目标对象的方法
        return method.invoke(target, args);
    }

    // 权限校验方法
    private boolean checkPermission(String userId) {
        return "admin".equals(userId) || "1001".equals(userId);
    }

    // 生成代理对象的方法
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new PermissionInvocationHandler(target)
        );
    }
}

JDK动态代理测试

测试动态代理的效果:

public class JdkProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService targetService = new UserServiceImpl();
        // 生成动态代理对象
        UserService proxyService = (UserService) PermissionInvocationHandler.getProxy(targetService);

        // 有权限的用户调用
        try {
            String result1 = proxyService.getUserInfo("admin");
            System.out.println("调用结果:" + result1);
        } catch (Exception e) {
            System.out.println("调用失败:" + e.getMessage());
        }

        // 无权限的用户调用
        try {
            String result2 = proxyService.getUserInfo("1003");
            System.out.println("调用结果:" + result2);
        } catch (Exception e) {
            System.out.println("调用失败:" + e.getMessage());
        }
    }
}

两种实现方式对比

两种方式都可以实现前置权限校验,适用场景有所不同:

对比项静态代理JDK动态代理
实现复杂度需要手动编写代理类,接口多时冗余代码多不需要手动编写代理类,实现更灵活
目标对象要求不需要目标对象实现接口要求目标对象必须实现接口
适用场景接口数量少、代理逻辑简单的场景接口数量多、需要统一增强的场景

注意事项

  • 权限校验逻辑需要尽量通用,避免和具体业务方法强耦合,方便后续扩展其他校验规则
  • 如果目标对象没有实现接口,可以使用CGLIB动态代理,通过继承目标类生成代理对象,实现方式和JDK动态代理类似
  • 代理模式只适合做方法级别的前置增强,复杂的权限控制建议结合专业的权限框架实现

代理模式权限校验前置增强方法调用动态代理修改时间:2026-07-09 16:42:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。