springboot切面编程

发布于:2025-07-03 ⋅ 阅读:(14) ⋅ 点赞:(0)

SpringBoot切面编程

众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转。本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理。

何为AOP

AOP(Aspect OrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

利用AOP可以对我们边缘业务进行隔离,降低无关业务逻辑耦合性。提高程序的可重用性,同时提高了开发的效率。一般用于日志记录,性能统计,安全控制,权限管理,事务处理,异常处理,资源池管理。使用场景

AOP的一些核心概念

概念 定义 作用 示例
横切关注点 多个模块中共同涉及的功能,如日志、事务、权限等 分离通用功能,避免代码冗余 所有Service方法都需要记录执行时间
切面(Aspect) 封装横切关注点的模块,包含切入点和通知 将横切逻辑集中管理 定义一个日志切面,统一处理日志记录
连接点(Join Point) 程序执行中的特定点,如方法调用、字段修改等 作为切面织入的候选位置 某个Service方法被调用时
切入点(Pointcut) 定义切面作用的具体位置,通过表达式匹配连接点 精确控制切面影响的范围 匹配所有以save开头的方法
通知(Advice) 切面在连接点执行的操作,分为前置、后置、返回、异常、环绕通知 实现具体的横切功能 在方法执行前记录参数,执行后记录返回值
织入(Weaving) 将切面与目标对象连接并创建代理对象的过程 使切面逻辑在特定时机生效 编译时织入(AspectJ)、运行时织入(Spring AOP)
目标对象(Target) 被切面包裹的对象 被增强的原始业务对象 实际的UserService类
代理对象(Proxy) 织入切面后生成的对象 替代原始对象,执行时包含切面逻辑 通过JDK动态代理生成的UserService代理对象

代码实现

这段代码展示了AOP(面向切面编程)在权限校验场景中的典型应用。通过自定义注解和环绕通知,实现了方法级别的权限拦截,避免了在每个业务方法中重复编写权限校验逻辑。

1. 自定义注解 @AuthCheck
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
    String mustRole() default "";
}
  • 作用:标记需要进行权限校验的方法,并指定所需的角色(如@AuthCheck(mustRole = "ADMIN"))。
  • 元注解
    • @Target(ElementType.METHOD):注解仅可用于方法。
    • @Retention(RetentionPolicy.RUNTIME):注解在运行时保留,以便反射获取。
2. 切面类 AuthInterceptor
@Aspect
@Component
public class AuthInterceptor {
    @Resource
    private UserService userService;

    @Around("@annotation(authCheck)")
    public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
        // 1. 获取注解中指定的必须角色
        String mustRole = authCheck.mustRole();
        
        // 2. 获取当前登录用户
        HttpServletRequest request = ((ServletRequestAttributes) 
            RequestContextHolder.getRequestAttributes()).getRequest();
        User loginUser = userService.getLoginUser(request);
        
        // 3. 权限校验逻辑
        UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
        if (mustRoleEnum == null) return joinPoint.proceed(); // 无需权限,放行
        
        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());
        if (userRoleEnum == null) throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        
        // 管理员权限校验
        if (mustRoleEnum == UserRoleEnum.ADMIN && userRoleEnum != UserRoleEnum.ADMIN) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        
        // 校验通过,执行原方法
        return joinPoint.proceed();
    }
}
  • 关键元素
    • @Aspect:声明该类为切面。
    • @Component:将切面注册为Spring Bean。
    • @Around("@annotation(authCheck)")
      • 环绕通知,拦截所有标记了@AuthCheck注解的方法。
      • authCheck参数绑定当前方法上的@AuthCheck注解实例。

AOP思想的体现

1. 关注点分离
  • 业务逻辑(如用户服务)与权限校验完全解耦。
  • 权限校验逻辑集中在切面中,无需在每个业务方法中重复编写。
2. 声明式编程
  • 通过@AuthCheck注解在方法上声明所需权限,简洁直观。
  • 示例:
    @AuthCheck(mustRole = "ADMIN")
    public void deleteUser(Long userId) {
        // 业务逻辑(无需关心权限校验)
    }
    
3. 动态代理机制
  • Spring AOP通过动态代理(JDK或CGLIB)在运行时生成代理对象。
  • 代理对象在调用目标方法前后插入权限校验逻辑:
    调用代理方法 → 执行前置校验 → 执行目标方法 → 执行后置逻辑
    

执行流程

  1. 方法调用:客户端调用标记了@AuthCheck的方法。
  2. 代理拦截:Spring AOP拦截调用,执行AuthInterceptor的环绕通知。
  3. 权限校验
    • 从注解获取所需角色(如ADMIN)。
    • 从当前请求获取登录用户信息。
    • 比较用户角色与注解要求的角色。
  4. 结果处理
    • 校验通过:执行原方法。
    • 校验失败:抛出BusinessException

网站公告

今日签到

点亮在社区的每一天
去签到