当前位置: 首页 > news >正文

Spring AOP详细解析

AOP

AOP:面向切面编程,将与业务无关,却为业务所共同调用的逻辑封装起来,减少系统的重复度,降低模块间的耦合度。对于一些“弱共性”。AOP可以同一对他们进行抽象和集中处理

AspectJ:切面,@ Aspect

JoinPoint:连接点,程序执行过程中的可被切面拦截的特定点

Advice:通知,定义横切逻辑

  1. @Before: 在方法之前执行增强
  2. @ After在方法之后执行通知
  3. @ Around:在方法执行前后都通知
  4. @ AfterReturning:在方法执行后返回结果执行通知
  5. @ AfterThrowing: 在方法抛出异常后执行通知

PointCut:切点,匹配连接点

@Pointcut("execution(public * com.neilxu..*Controller.*(..))")

AOP实现机制-基于动态代理

动态代理:运行时动态生成代理对象,允许开发者运行时指定需要代理的接口和行为,在不修改原始类的情况下对方法调用进行增强和拦截。

基于JDK的动态代理:基于reflect包的Proxy和InvolationHandler接口实现,需要代理的类实现一个或者多个接口

基于CGLIB的动态代理:当代理的类没有实现接口时,使用CGLIB生成被代理类的子类作为代理

能使用静态代理的方式实现AOP吗?

AOP首先在切面(Aspect)中定义一个Advice(增强),将advice织入到对象的方法中

可以,但是有较多缺点:

  1. 代码爆炸:假如有100个Service类需要加事务,就需要写100个静态代理类
  2. 僵化:一旦业务改名,所以相关的代理类都得改名
  3. 无法动态筛选:假如只想给某个注解得方法加事务,静态代理必须写死逻辑
package com.neilxu.train.member.aspect;import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;@Aspect
@Component
public class LogAspect {public LogAspect() {System.out.println("LogAspect");}private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);/*** 定义一个切点*///任意返回类型,neilxu下任意包(项目名/模块名),任意Controller类下任意方法任意参数@Pointcut("execution(public * com.neilxu..*Controller.*(..))")public void controllerPointcut() {}@Before("controllerPointcut()")public void doBefore(JoinPoint joinPoint) {// 增加日志流水号MDC.put("LOG_ID", System.currentTimeMillis() + RandomUtil.randomString(3));// 开始打印请求日志ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();Signature signature = joinPoint.getSignature();String name = signature.getName();// 打印请求信息LOG.info("------------- 开始 -------------");LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);LOG.info("远程地址: {}", request.getRemoteAddr());// 打印请求参数Object[] args = joinPoint.getArgs();// LOG.info("请求参数: {}", JSONObject.toJSONString(args));// 排除特殊类型的参数,如文件类型Object[] arguments = new Object[args.length];for (int i = 0; i < args.length; i++) {if (args[i] instanceof ServletRequest|| args[i] instanceof ServletResponse|| args[i] instanceof MultipartFile) {continue;}arguments[i] = args[i];}// 排除字段,敏感字段或太长的字段不显示:身份证、手机号、邮箱、密码等String[] excludeProperties = {"mobile"};PropertyPreFilters filters = new PropertyPreFilters();PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();excludefilter.addExcludes(excludeProperties);LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));}@Around("controllerPointcut()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {long startTime = System.currentTimeMillis();Object result = proceedingJoinPoint.proceed();// 排除字段,敏感字段或太长的字段不显示:身份证、手机号、邮箱、密码等String[] excludeProperties = {"mobile"};PropertyPreFilters filters = new PropertyPreFilters();PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();excludefilter.addExcludes(excludeProperties);LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);return result;}}

http://www.lryc.cn/news/605136.html

相关文章:

  • [硬件电路-106]:模拟电路 - 电路为什么会出现不同的频率特性?元件频率依赖性、信号传输路径、电路拓扑结构、外部因素
  • 【maven】仓库配置
  • Matrix Theory study notes[6]
  • USRP捕获手机/路由器数据传输信号波形(上)
  • ZKMall商城开源本地部署指南
  • Apache Ignite 集群标识(Cluster ID)和集群标签(Cluster Tag)
  • 【物联网】基于树莓派的物联网开发【18】——树莓派安装Mosquitto服务
  • anaconda和Miniconda安装包32位64位皆可,anaconda和Miniconda有什么区别?
  • 2419. 按位与最大的最长子数组
  • 【 建模分析回顾】[MultiOutputClassifier]MAP - Charting Student Math Misunderstandings
  • mac升级安装python3
  • LeetCode 53 - 最大子数组和
  • 【Unity3D实例-功能-移动】复杂移动(Blend Tree方式)
  • JeecgBoot(1):前后台环境搭建
  • 【Excel】制作双重饼图
  • Linux设备驱动架构相关文章
  • 学习日志22 python
  • CUDA编程9 - 卷积实践
  • Python - 元类
  • 离散扩散模型在数独问题上的复现与应用
  • RAG工作流程总览
  • 解析非法获取计算机信息系统数据罪中的其他技术手段
  • 《超级秘密文件夹》密码遗忘?试用版/正式版找回教程(附界面操作步骤)
  • IATF 16949详解(腾讯混元)
  • Oracle11g数据库迁移达梦8数据库方案
  • 论文阅读|CVPR 2025|Mamba进一步研究|GroupMamba
  • 领域驱动设计(DDD)在分布式系统中的架构实践
  • cpp实现音频重采样8k->16k及16k->8k
  • 不同环境安装配置redis
  • 网络端口号全景解析:从基础服务到特殊应用的完整指南