SpringBoot下使用AOP做日志
AOP实现接口执行时间的计算:
- SpringBoot项目导入spring-boot-starter-aop依赖
- 编写切面类
- 类上加@Aspect注解,表明这是一个切面类
- 类上加@Component,把切面交给Spring管理(我们要切的Controller/Service都是Spring容器的,切面要对它们起作用,就必须同样进入容器)
- 类内部配置切点表达式,比如@Pointcut("execution(* com.bravo.demo.controller.*.*(..))") 表示对com.bravo.demo.controller包下所有方法进行增强
- 类内部编写增强逻辑,通常使用@Before、@Around声明这是一个增强,不同的注解增强的方式不同,比如@Before前置增强、@Around环绕增强
1、导入AOP整合SpringBoot依赖
1 2 3 4 5 | <!--SpringBoot整合Aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> |
2、编写切面类:com.zhixi.config.aop.ApiTimeLogAspect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import lombok. extern .slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @ClassName ApiTimeLogAspect * @Author zhangzhixi * @Description * @Date 2022-4-15 10:42 * @Version 1.0 */ @Slf4j /*第一步:声明这是一个切面类*/ @Aspect @Component public class ApiTimeLogAspect { /** * 第二步:定义切点表达式,明确要对那些方法起作用(比如,只对com.bravo.demo.controller包的方法计算接口耗时) */ @Pointcut( "execution(* com.zhixi.controller.*.*(..))" ) public void controllerPointcut() { } /** * 第三步:1.通过引用切点表达式,明确这个增强的应用规则。 2.编写增强逻辑 * * @param proceedingJoinPoint 执行目标方法的参数 * @return 返回目标方法的执行结果 * @throws Throwable proceedingJoinPoint.proceed()方法抛出的异常 */ @Around(value = "controllerPointcut()" ) public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 记录接口执行前的时间戳 long startTime = System.currentTimeMillis(); // 实际执行目标方法,类似动态代理的invoke()执行目标方法 Object result = proceedingJoinPoint.proceed(); // 计算接口耗时 log.info( "------------ 耗时: {} ms ------------" , System.currentTimeMillis() - startTime); // 只做增强不做改变,还是要把接口原本的结果返回 return result; } } |
3、启动项目访问接口即可
AOP获取请求的浏览器信息
1、依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <dependencies> <!--Lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--fastjson依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> <!--获取浏览器信息--> <dependency> <groupId>eu.bitwalker</groupId> <artifactId>UserAgentUtils</artifactId> <version>1.21</version> </dependency> <!--SpringBoot整合Aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--SpringBoot-Web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> |
2、工具类(对上一版进行了优化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | package com.zhixi.util; import eu.bitwalker.useragentutils.Browser; import eu.bitwalker.useragentutils.OperatingSystem; import eu.bitwalker.useragentutils.UserAgent; import eu.bitwalker.useragentutils.Version; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; public class IpAndAddrUtil { private static final String UNKNOWN = "unknown" ; private static final String[] PROXY_HEADERS = { "x-forwarded-for" , "Proxy-Client-IP" , "WL-Proxy-Client-IP" }; /** * 获取发起请求的IP地址 */ public static String getIp(HttpServletRequest request) { String ip = null ; for (String header : PROXY_HEADERS) { ip = request.getHeader(header); if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) { break ; } } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); if ( "127.0.0.1" . equals (ip)) { try { ip = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } } } if (ip != null && ip.length() > 15) { if (ip.indexOf( "," ) > 0) { ip = ip.substring(0, ip.indexOf( "," )); } } return ip; } /** * 获取发起请求的浏览器名称 */ public static String getBrowserName(HttpServletRequest request) { UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader( "User-Agent" )); Browser browser = userAgent.getBrowser(); return browser.getName(); } /** * 获取发起请求的浏览器版本号 */ public static String getBrowserVersion(HttpServletRequest request) { UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader( "User-Agent" )); Browser browser = userAgent.getBrowser(); Version version = browser.getVersion(request.getHeader( "User-Agent" )); return version == null ? null : version.getVersion(); } /** * 获取发起请求的操作系统名称 */ public static String getOsName(HttpServletRequest request) { UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader( "User-Agent" )); OperatingSystem os = userAgent.getOperatingSystem(); return os.getName(); } } |
3、AOP:前置通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | package com.zhixi.aop; import com.alibaba.fastjson.JSONObject; import com.zhixi.util.IpAndAddrUtil; import lombok. extern .slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; @Aspect @Component @Slf4j public class LogBrowserAspect { @Pointcut( "execution(* com.zhixi.controller.*.*(..))" ) public void webLog() { } @Before( "webLog()" ) public void doBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert attributes != null ; HttpServletRequest request = attributes.getRequest(); /*获取请求IP*/ String requestIp = IpAndAddrUtil.getIp(request); /*获取发起请求的浏览器版本号*/ String browserVersion = IpAndAddrUtil.getBrowserVersion(request); /*获取发起请求的操作系统名称*/ String osName = IpAndAddrUtil.getOsName(request); /*获取发起请求的浏览器名称*/ String browserName = IpAndAddrUtil.getBrowserName(request); JSONObject jsonObject = new JSONObject(); jsonObject.put( "requestURL" , request.getRequestURL()); jsonObject.put( "ip" , requestIp); jsonObject.put( "browserVersion" , browserVersion); jsonObject.put( "osName" , osName); jsonObject.put( "browserName" , browserName); jsonObject.forEach((k, v) -> { log.info(k + ":" + v); }); } } |
4、测试
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人