二(8.4)注解和aop
1. AOP 是 Aspect-Oriented Programming面向切面编程。它常常和 Java 注解一起使用尤其在 Spring 里非常常见。可以简单理解为注解负责“标记哪里需要增强”AOP 负责“在这些地方自动插入增强逻辑”。比如LogExecutionTimepublicvoidcreateOrder(){// 创建订单}这个方法本身只关心“创建订单”而 LogExecutionTime 表示这个方法需要记录执行时间。真正记录时间的逻辑可以交给 AOP 自动处理。2. AOP 是什么AOP 的核心思想是把一些和业务无关、但很多地方都需要的通用逻辑抽出来统一处理。常见场景包括日志记录 权限校验 事务管理 接口限流 性能监控 异常处理 缓存处理 审计记录比如一个订单服务publicvoidcreateOrder(){checkPermission();startTransaction();// 真正的业务逻辑saveOrder();commitTransaction();log();}如果每个方法都这样写业务代码会变得很乱。AOP 的作用就是让业务方法保持干净publicvoidcreateOrder(){saveOrder();}而权限、事务、日志这些逻辑由 AOP 在方法执行前后自动加进去。3. AOP 的几个核心概念3.1. 切面 Aspect切面就是一组横切逻辑的集合。比如“日志切面”“权限切面”“事务切面”。AspectComponentpublicclassLogAspect{}3.2. 连接点 Join Point连接点是程序执行过程中的某个点。在 Spring AOP 里通常指的是“方法调用”。比如userService.createUser()orderService.createOrder()这些方法执行点都可以被 AOP 拦截。3.3. 切点 Pointcut切点用来指定哪些方法需要被拦截。比如拦截所有 service 包下的方法Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceMethods(){}也可以拦截带有某个注解的方法Pointcut(annotation(com.example.annotation.LogExecutionTime))publicvoidlogExecutionTimeMethods(){}3.4. 通知 Advice通知就是“什么时候执行增强逻辑”。常见通知类型Before方法执行前After方法执行后不管是否异常AfterReturning方法正常返回后AfterThrowing方法抛异常后Around包围方法执行最强大例如Before(serviceMethods())publicvoidbefore(){System.out.println(方法执行前);}2. 注解和 AOP 如何配合通常分三步。第一步定义一个注解Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceLogExecutionTime{}解释一下Target(ElementType.METHOD)表示这个注解只能加在方法上。Retention(RetentionPolicy.RUNTIME)表示这个注解在运行时仍然保留这样 AOP 才能在运行时识别它。第二步在业务方法上使用注解ServicepublicclassOrderService{LogExecutionTimepublicvoidcreateOrder(){System.out.println(创建订单);}}这时 createOrder() 被标记为“需要记录执行时间”。第三步用 AOP 拦截这个注解AspectComponentpublicclassLogAspect{Around(annotation(com.example.annotation.LogExecutionTime))publicObjectlogExecutionTime(ProceedingJoinPointjoinPoint)throwsThrowable{longstartSystem.currentTimeMillis();ObjectresultjoinPoint.proceed();longendSystem.currentTimeMillis();System.out.println(joinPoint.getSignature().getName() 执行耗时(end-start)ms);returnresult;}}核心是这一句Around(annotation(com.example.annotation.LogExecutionTime))意思是拦截所有加了 LogExecutionTime 注解的方法。而这一句joinPoint.proceed();表示执行原来的业务方法。所以执行流程大概是调用createOrder()↓ 进入AOP切面 ↓ 记录开始时间 ↓ 执行createOrder()原始方法 ↓ 记录结束时间 ↓ 打印耗时 ↓ 返回结果3. 一个更实际的例子权限校验定义注解Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceRequireRole{Stringvalue();}使用注解RequireRole(admin)publicvoiddeleteUser(LonguserId){// 删除用户}AOP 拦截Around(annotation(requireRole))publicObjectcheckRole(ProceedingJoinPointjoinPoint,RequireRolerequireRole)throwsThrowable{StringrequiredRolerequireRole.value();// 假设这里拿到当前用户角色StringcurrentRoleuser;if(!requiredRole.equals(currentRole)){thrownewRuntimeException(权限不足);}returnjoinPoint.proceed();}这样业务代码只需要写RequireRole(admin)不用在每个方法里手动写权限判断。4. 为什么注解适合配合 AOP因为注解本身不做事情它只是一个“标记”或“配置”。比如RequireRole(admin)它只是告诉系统这个方法需要 admin 权限。但真正的权限判断逻辑需要 AOP 去执行。所以它们的关系可以理解为注解声明意图AOP执行逻辑