建设商城购物网站外贸网站优化价格

张小明 2026/1/2 19:17:32
建设商城购物网站,外贸网站优化价格,网站 备案 名称,企业邮箱多少钱一年Spring AOP 面向切面编程完全指南 #x1f680; 一、什么是 AOP#xff1f; #x1f914; 面向切面编程#xff08;AOP#xff09;是 Spring 框架的核心功能之一#xff0c;它允许开发者将横切关注点#xff08;如日志记录、事务管理、安全控制等#xff09;从业务逻…Spring AOP 面向切面编程完全指南 一、什么是 AOP 面向切面编程AOP是 Spring 框架的核心功能之一它允许开发者将横切关注点如日志记录、事务管理、安全控制等从业务逻辑中分离出来实现代码的模块化和复用。就像电影特效团队他们专注于特效制作而不需要关心剧本内容二、快速开始 ⚡1. 导入依赖 !-- Spring Boot AOP 依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency2. 第一个 AOP 程序方法执行时间监控 ⏱️Slf4jAspect// 声明为切面类 Component// 交给 IOC 容器管理 publicclassRecordTimeAspect{/** * 切入点表达式监控 com.example.service 包下所有类的所有方法 */Around(execution(* com.example.service.*.*(..)))publicObjectrecordTime(ProceedingJoinPointpjp)throwsThrowable{// 记录开始时间longbeginTimeSystem.currentTimeMillis();// 执行原始方法 ‍♂️Objectresultpjp.proceed();// 记录结束时间并计算耗时longendTimeSystem.currentTimeMillis();longcostTimeendTime-beginTime;// 获取方法签名信息StringmethodNamepjp.getSignature().getName();StringclassNamepjp.getTarget().getClass().getSimpleName();log.info( [{}] - [{}] 执行耗时: {}ms,className,methodName,costTime);returnresult;}}三、AOP 核心概念详解 1. 核心术语 概念说明类比表情连接点 (JoinPoint)程序执行过程中可以插入切面的点电影中的每个场景通知 (Advice)切面在特定连接点执行的动作特效团队的工作切入点 (Pointcut)匹配连接点的谓词需要加特效的场景切面 (Aspect)通知和切入点的组合完整的特效设计方案目标对象 (Target)被一个或多个切面所通知的对象原始电影片段2. AOP 底层原理动态代理 ‍♂️Spring AOP 默认使用两种代理方式JDK 动态代理基于接口实现 ✨CGLIB 代理基于继承实现 四、通知类型详解 1. 五种通知类型 ️AspectComponentpublicclassAllAdviceExample{/** * 1. 环绕通知 - 最强大的通知类型 */Around(execution(* com.example.service.*.*(..)))publicObjectaroundAdvice(ProceedingJoinPointpjp)throwsThrowable{log.info( Around - 方法执行前);try{Objectresultpjp.proceed();// 必须显式调用原始方法log.info(✅ Around - 方法执行后);returnresult;}catch(Exceptione){log.error(❌ Around - 方法执行异常);throwe;}}/** * 2. 前置通知 - 在目标方法执行前执行 ⬆️ */Before(execution(* com.example.service.*.*(..)))publicvoidbeforeAdvice(JoinPointjoinPoint){log.info(⬆️ Before - 方法执行前);}/** * 3. 后置通知 - 在目标方法执行后执行无论是否异常 ⬇️ */After(execution(* com.example.service.*.*(..)))publicvoidafterAdvice(JoinPointjoinPoint){log.info(⬇️ After - 方法执行后总执行);}/** * 4. 返回后通知 - 在目标方法正常返回后执行 ✅ */AfterReturning(valueexecution(* com.example.service.*.*(..)),returningresult)publicvoidafterReturningAdvice(JoinPointjoinPoint,Objectresult){log.info(✅ AfterReturning - 方法正常返回结果: {},result);}/** * 5. 异常通知 - 在目标方法抛出异常后执行 ❌ */AfterThrowing(valueexecution(* com.example.service.*.*(..)),throwingex)publicvoidafterThrowingAdvice(JoinPointjoinPoint,Exceptionex){log.error(❌ AfterThrowing - 方法执行异常: {},ex.getMessage());}}2. 通知执行顺序 默认执行顺序同一切面内 Around前半部分 →⬆️ Before→ 目标方法→ Around后半部分 →✅ AfterReturning/❌ AfterThrowing→⬇️ After五、切入点表达式 ✨1. execution 表达式 AspectComponentpublicclassPointcutExamples{// 1. 抽取公共切入点表达式 Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}// 2. 精确匹配方法 Pointcut(execution(public String com.example.service.UserService.getUserById(Integer)))publicvoidspecificMethod(){}// 3. 匹配包下所有方法 Pointcut(execution(* com.example.service..*.*(..)))// ..表示子包publicvoidallServiceMethods(){}// 4. 匹配特定注解的方法 ️Pointcut(annotation(com.example.annotation.Log))publicvoidlogAnnotation(){}// 5. 组合切入点表达式 Pointcut(serviceLayer() !specificMethod())publicvoidserviceButNotSpecific(){}Around(serviceLayer())// 引用切入点表达式publicObjectadviceMethod(ProceedingJoinPointpjp)throwsThrowable{// 业务逻辑returnpjp.proceed();}}2. annotation 表达式基于注解 ️/** * 自定义日志注解 */Target(ElementType.METHOD)// 只能用在方法上Retention(RetentionPolicy.RUNTIME)// 运行时生效publicinterfaceLog{Stringvalue()default;booleanrecordParams()defaulttrue;booleanrecordResult()defaulttrue;}六、实战操作日志记录到数据库 1. 创建操作日志实体 DataTableName(t_operate_log)// MyBatis-Plus 注解publicclassOperateLog{TableId(typeIdType.AUTO)privateLongid;privateLongoperateUserId;// 操作人ID privateStringoperateUserName;// 操作人姓名JsonFormat(patternyyyy-MM-dd HH:mm:ss)privateLocalDateTimeoperateTime;// 操作时间 ⏰privateStringclassName;// 类名privateStringmethodName;// 方法名TableField(typeHandlerJacksonTypeHandler.class)privateObjectmethodParams;// 方法参数JSON格式 TableField(typeHandlerJacksonTypeHandler.class)privateObjectreturnValue;// 返回值JSON格式 privateBooleansuccess;// 操作是否成功 ✅privateStringerrorMessage;// 错误信息 ❌privateLongcostTime;// 耗时毫秒 ⏱️privateStringclientIp;// 客户端IP privateStringrequestUri;// 请求URI }2. Mapper 接口 MapperpublicinterfaceOperateLogMapperextendsBaseMapperOperateLog{// 这里可以添加自定义查询方法}3. 用户上下文工具类ThreadLocal ComponentpublicclassUserContext{privatestaticfinalThreadLocalCurrentUserUSER_CONTEXTnewThreadLocal();/** * 设置当前用户信息 */publicstaticvoidsetCurrentUser(CurrentUseruser){USER_CONTEXT.set(user);}/** * 获取当前用户ID */publicstaticLonggetCurrentUserId(){CurrentUseruserUSER_CONTEXT.get();returnuser!null?user.getId():null;}/** * 获取当前用户信息 */publicstaticCurrentUsergetCurrentUser(){returnUSER_CONTEXT.get();}/** * 清除用户信息防止内存泄漏 */publicstaticvoidclear(){USER_CONTEXT.remove();}DatapublicstaticclassCurrentUser{privateLongid;privateStringusername;privateStringname;privateStringrole;}}4. 切面类实现 ️Slf4jAspectComponentpublicclassOperateLogAspect{AutowiredprivateOperateLogMapperoperateLogMapper;AutowiredprivateHttpServletRequestrequest;/** * 基于注解的切入点 */Around(annotation(logAnnotation))publicObjectlogOperate(ProceedingJoinPointpjp,LoglogAnnotation)throwsThrowable{// 记录开始时间 ⏰longstartTimeSystem.currentTimeMillis();// 创建日志对象 OperateLogoperateLognewOperateLog();operateLog.setOperateTime(LocalDateTime.now());operateLog.setSuccess(true);// 获取方法信息 MethodSignaturesignature(MethodSignature)pjp.getSignature();Methodmethodsignature.getMethod();// 设置基本信息operateLog.setClassName(pjp.getTarget().getClass().getName());operateLog.setMethodName(method.getName());// 获取当前用户 LongcurrentUserIdUserContext.getCurrentUserId();operateLog.setOperateUserId(currentUserId);// 获取请求信息 if(request!null){operateLog.setClientIp(getClientIp(request));operateLog.setRequestUri(request.getRequestURI());}// 记录方法参数根据配置 if(logAnnotation.recordParams()){Object[]argspjp.getArgs();String[]paramNamessignature.getParameterNames();MapString,ObjectparamsnewHashMap();for(inti0;iargs.length;i){// 过滤掉敏感参数 if(!isSensitiveParam(paramNames[i])){params.put(paramNames[i],args[i]);}}operateLog.setMethodParams(params);}Objectresultnull;try{// 执行目标方法 ‍♂️resultpjp.proceed();// 记录返回值根据配置 ✅if(logAnnotation.recordResult()){operateLog.setReturnValue(result);}// 计算耗时 ⏱️longendTimeSystem.currentTimeMillis();operateLog.setCostTime(endTime-startTime);log.info(✅ 操作日志记录成功: {}.{},operateLog.getClassName(),operateLog.getMethodName());}catch(Throwablethrowable){// 记录异常信息 ❌operateLog.setSuccess(false);operateLog.setErrorMessage(throwable.getMessage());operateLog.setCostTime(System.currentTimeMillis()-startTime);log.error(❌ 操作执行失败: {},throwable.getMessage());throwthrowable;}finally{// 异步保存日志到数据库 saveLogAsync(operateLog);}returnresult;}/** * 异步保存日志 */privatevoidsaveLogAsync(OperateLogoperateLog){CompletableFuture.runAsync(()-{try{operateLogMapper.insert(operateLog);log.debug( 操作日志已保存到数据库);}catch(Exceptione){log.error(❌ 保存操作日志失败: {},e.getMessage());}});}/** * 获取客户端IP地址 */privateStringgetClientIp(HttpServletRequestrequest){Stringiprequest.getHeader(X-Forwarded-For);if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getHeader(Proxy-Client-IP);}if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getHeader(WL-Proxy-Client-IP);}if(ipnull||ip.length()0||unknown.equalsIgnoreCase(ip)){iprequest.getRemoteAddr();}returnip;}/** * 判断是否为敏感参数 */privatebooleanisSensitiveParam(StringparamName){ListStringsensitiveParamsArrays.asList(password,token,secret);returnsensitiveParams.stream().anyMatch(paramName::contains);}}七、最佳实践与注意事项 ⚠️1. 性能优化建议 合理使用切入点表达式避免过于宽泛的匹配异步处理耗时操作如数据库日志保存缓存频繁访问的数据如方法签名信息2. 常见陷阱 ️自调用问题同一个类中方法互相调用AOP不会生效异常处理确保异常被正确处理和传播内存泄漏ThreadLocal使用后必须清理3. 调试技巧 // 在通知中打印详细信息Before(execution(* com.example..*.*(..)))publicvoiddebugAdvice(JoinPointjoinPoint){log.debug( 目标类: {},joinPoint.getTarget().getClass().getName());log.debug( 方法名: {},joinPoint.getSignature().getName());log.debug( 参数: {},Arrays.toString(joinPoint.getArgs()));}八、总结 Spring AOP 是一个强大的面向切面编程框架它通过动态代理机制实现了横切关注点的模块化。掌握 AOP 可以让你的代码更加✅干净整洁- 分离关注点✅易于维护- 集中化管理✅高度复用- 一处定义多处使用✅灵活扩展- 非侵入式增强希望这篇指南能帮助你更好地理解和使用 Spring AOPHappy coding! ‍‍小提示在实际项目中建议将AOP配置放在独立的配置类中便于管理和维护。记得根据具体业务场景选择合适的通知类型和切入点表达式哦✨
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

南京建网站公司电商网站怎么做微信支付

第一章:协程调度到底难在哪?一线专家亲授5年实战经验 协程调度的复杂性远超表面所见,其核心挑战在于如何在高并发场景下实现资源的高效利用与上下文切换的低开销。许多开发者误以为启用协程只是“启动即完成”,但实际生产环境中&a…

张小明 2026/1/1 20:39:17 网站建设

三亚网站建设哪家好绍兴网站建设公司地址

在现代生命科学的研究中,抗体作为关键工具,广泛应用于免疫学、细胞生物学及药物开发等多个领域。其中,针对肿瘤坏死因子α(TNFα)及其受体(TNFSF2)的抗体,因其在炎症反应、自身免疫疾…

张小明 2025/12/30 18:14:07 网站建设

网站工作室模板哪些做调查问卷挣钱的网站

调试、跟踪与性能分析指南 在软件开发和系统优化过程中,调试、跟踪和性能分析是至关重要的环节。本文将详细介绍相关的工具和技术,帮助你更好地理解和优化系统与应用程序的性能。 设置探针的语法与参数 设置探针时,我们使用以下语法: <type>:<event name>…

张小明 2025/12/29 8:58:39 网站建设

老域名怎么做新网站网站建设 报价

这里写目录标题项目展示详细视频演示技术栈文章下方名片联系我即可~解决的思路开发技术介绍性能/安全/负载方面python语言Django框架介绍技术路线关键代码详细视频演示收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目展示 项目编号&#xff…

张小明 2025/12/29 8:58:02 网站建设

绿色大气网站模板马云的网站怎么做的

第一章&#xff1a;Open-AutoGLM长按异常问题的背景与影响 在现代智能设备交互中&#xff0c;长按操作是一种常见且关键的用户输入方式&#xff0c;广泛应用于文本选择、快捷菜单触发和上下文操作等场景。Open-AutoGLM作为一款基于大语言模型驱动的自动化交互框架&#xff0c;在…

张小明 2025/12/31 6:00:51 网站建设

让网站快速收录新闻录入网站模板

Velero性能调优实战指南&#xff1a;5个关键策略解决Kubernetes备份瓶颈 【免费下载链接】velero Backup and migrate Kubernetes applications and their persistent volumes 项目地址: https://gitcode.com/GitHub_Trending/ve/velero 在Kubernetes集群规模不断扩大的…

张小明 2026/1/1 20:28:24 网站建设