ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

初步理解 AOP

初步理解 AOP 初步理解 AOPAOPAspect-Oriented Programming面向切面编程是对 OOP面向对象编程的补充。它要解决的核心问题是把那些散落在各个业务方法中的重复逻辑如日志、事务、权限、缓存抽取出来集中管理让业务代码只关注业务本身。一、为什么需要 AOP假设你写了一个用户注册方法publicvoidregister(Useruser){log.info(开始注册用户user.getName());// 日志longstartSystem.currentTimeMillis();// 性能监控if(!currentUser.hasPermission(user:add)){// 权限校验thrownewPermissionDeniedException();}userDao.save(user);// 真正的业务longcostSystem.currentTimeMillis()-start;// 性能监控log.info(注册完成耗时costms);// 日志}真正的业务只有userDao.save(user)一行其他都是“横切关注点”。如果每个方法都这样写代码会变得臃肿、重复、难以维护。AOP 就是把这些横切逻辑从业务方法中抽离出去统一放到“切面”里。二、AOP 的核心概念概念说明类比切面Aspect横切关注点的模块化包含切点和通知一个日志处理类连接点Join Point程序执行中可以插入切面的点通常是方法调用每个可以被拦截的方法切点Pointcut匹配连接点的表达式定义“在哪里”织入execution(* com.example.service.*.*(..))通知Advice在切点上执行的具体动作定义“做什么”log.info(方法执行)织入Weaving把切面应用到目标对象并创建代理的过程Spring 运行时生成代理对象目标对象Target被切面增强的原始业务对象UserServiceImpl实例代理Proxy织入后生成的代理对象包含增强逻辑$Proxy12或 CGLIB 子类一句话切点定义在哪里拦截通知定义拦截后做什么切面把它们组合在一起通过代理织入到目标对象。三、五种通知类型通知注解执行时机前置通知Before目标方法执行前后置通知After目标方法执行后无论是否异常返回通知AfterReturning目标方法正常返回后异常通知AfterThrowing目标方法抛出异常后环绕通知Around目标方法执行前后最强大AspectComponentpublicclassLogAspect{Before(execution(* com.example.service.*.*(..)))publicvoidbefore(JoinPointjp){System.out.println(执行前jp.getSignature().getName());}AfterReturning(pointcutexecution(* com.example.service.*.*(..)),returningresult)publicvoidafterReturning(JoinPointjp,Objectresult){System.out.println(返回结果result);}Around(execution(* com.example.service.*.*(..)))publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{longstartSystem.currentTimeMillis();Objectresultpjp.proceed();// 执行目标方法longcostSystem.currentTimeMillis()-start;System.out.println(耗时costms);returnresult;}}四、AOP 的实现方式Spring AOP 底层使用动态代理目标类实现了接口 → 默认使用 JDK 动态代理。目标类没有接口 → 使用 CGLIB 动态代理。Spring Boot 默认强制使用 CGLIB。代理对象在运行时生成拦截目标方法调用在调用前后插入通知逻辑。// 伪代码代理对象内部publicclassUserServiceProxyimplementsUserService{privateUserServicetarget;publicvoidregister(Useruser){// 前置通知log.info(开始注册);// 调用目标方法target.register(user);// 后置通知log.info(注册完成);}}五、AOP 能做什么场景说明日志记录统一记录方法调用日志事务管理Transactional自动开启/提交/回滚事务权限校验方法执行前检查用户权限性能监控统计方法执行耗时缓存Cacheable先查缓存未命中才执行方法异常处理统一捕获异常并记录六、快速上手示例1. 引入依赖Spring BootdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency2. 定义切面AspectComponentpublicclassTimeAspect{Around(execution(* com.example.service.*.*(..)))publicObjectmeasureTime(ProceedingJoinPointpjp)throwsThrowable{longstartSystem.currentTimeMillis();Objectresultpjp.proceed();longcostSystem.currentTimeMillis()-start;System.out.println(pjp.getSignature().getName() 耗时costms);returnresult;}}3. 调用 Service 方法ServicepublicclassUserService{publicvoidregister(Useruser){System.out.println(注册用户user.getName());}}执行userService.register(user)时控制台会输出注册用户张三 register 耗时0ms业务代码中没有任何日志或监控代码增强逻辑完全由切面处理。七、注意事项内部调用失效同一个类中方法 A 调用方法 BB 的增强不会生效。因为内部调用走的是原始对象不是代理对象。ServicepublicclassUserService{publicvoidmethodA(){methodB();// 不经过代理增强失效}TransactionalpublicvoidmethodB(){}}切点表达式要准确execution(* com.example.service.*.*(..))只匹配service包下的类。写错包名或方法签名会导致增强不生效。不要滥用 AOPAOP 适合处理横切关注点不适合替代正常的业务逻辑。过度使用会让代码难以追踪。八、总结AOP 的核心思想是把横切关注点从业务代码中分离出来通过代理在运行时织入。它让业务方法保持纯净同时获得日志、事务、权限等通用能力。关键点说明解决的问题横切逻辑重复、耦合高核心概念切面、切点、通知、连接点、织入、代理通知类型Before、After、AfterReturning、AfterThrowing、Around底层实现JDK 动态代理 / CGLIB典型应用日志、事务、权限、缓存、监控注意事项内部调用失效、切点表达式准确理解 AOP就理解了 Spring 为什么能在不修改业务代码的情况下为方法添加事务、缓存、日志等能力。这是 Spring 框架最核心的设计思想之一。
返回列表