最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot使用AOP切面對請求進(jìn)行日志記錄方式

 更新時(shí)間:2025年05月21日 09:06:09   作者:小馬不敲代碼  
這篇文章主要介紹了SpringBoot使用AOP切面對請求進(jìn)行日志記錄方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

簡介

AOP(Aspect-Oriented Programming,面向切面編程)是一種編程范式,旨在通過分離橫切關(guān)注點(diǎn)(cross-cutting concerns)來提高代碼的模塊化。

橫切關(guān)注點(diǎn)是指那些跨越多個(gè)模塊的功能,例如日志記錄、事務(wù)管理、安全性檢查等。

AOP 通過將這些功能從核心業(yè)務(wù)邏輯中分離出來,使代碼更易于維護(hù)和擴(kuò)展。

核心概念

1、切面(Aspect):

  • 切面是橫切關(guān)注點(diǎn)的模塊化實(shí)現(xiàn)。它包含通知(Advice)和切點(diǎn)(Pointcut)。
  • 例如,日志記錄功能可以作為一個(gè)切面。

2、連接點(diǎn)(Join Point):

  • 連接點(diǎn)是程序執(zhí)行過程中的特定點(diǎn),例如方法調(diào)用、異常拋出等。
  • AOP 可以在這些點(diǎn)上插入額外的行為。

3、通知(Advice):

  • 通知是切面在特定連接點(diǎn)執(zhí)行的動(dòng)作。常見的通知類型包括:
  • 前置通知(Before Advice):在目標(biāo)方法執(zhí)行之前執(zhí)行。
  • 后置通知(After Advice):在目標(biāo)方法執(zhí)行之后執(zhí)行。
  • 返回通知(After Returning Advice):在目標(biāo)方法成功返回后執(zhí)行。
  • 異常通知(After Throwing Advice):在目標(biāo)方法拋出異常后執(zhí)行。
  • 環(huán)繞通知(Around Advice):在目標(biāo)方法執(zhí)行前后都執(zhí)行,可以控制是否執(zhí)行目標(biāo)方法。

4、切點(diǎn)(Pointcut):

  • 切點(diǎn)用于定義哪些連接點(diǎn)會(huì)觸發(fā)通知。它通過表達(dá)式或規(guī)則匹配連接點(diǎn)。
  • 例如,匹配所有以 save 開頭的方法。

5、引入(Introduction):

  • 引入允許向現(xiàn)有類添加新的方法或?qū)傩?,而無需修改類的源代碼。

6、目標(biāo)對象(Target Object):

目標(biāo)對象是被一個(gè)或多個(gè)切面通知的對象,通常是核心業(yè)務(wù)邏輯的類。

7、代理(Proxy):

  • AOP 框架通過創(chuàng)建代理對象來實(shí)現(xiàn)切面功能。
  • 代理對象在目標(biāo)對象的方法調(diào)用前后插入通知。

AOP 的實(shí)現(xiàn)方式

1、靜態(tài)代理:

在編譯時(shí)生成代理類,例如 AspectJ 的編譯時(shí)織入。

2、動(dòng)態(tài)代理:

在運(yùn)行時(shí)生成代理類,例如 Spring AOP 使用的 JDK 動(dòng)態(tài)代理或 CGLIB。

AOP 的應(yīng)用場景

1、日志記錄:

在方法調(diào)用前后記錄日志,而不需要在每個(gè)方法中手動(dòng)添加日志代碼。

2、事務(wù)管理:

在方法執(zhí)行前后管理事務(wù)的開啟、提交或回滾。

3、安全性檢查:

在方法調(diào)用前檢查用戶權(quán)限。

4、性能監(jiān)控:

在方法執(zhí)行前后記錄時(shí)間,用于性能分析。

5、異常處理:

在方法拋出異常時(shí)執(zhí)行特定的處理邏輯。

AOP 的優(yōu)點(diǎn)

1、模塊化:

將橫切關(guān)注點(diǎn)從核心業(yè)務(wù)邏輯中分離出來,使代碼更清晰、更易于維護(hù)。

2、代碼復(fù)用:

通過切面實(shí)現(xiàn)通用功能,避免重復(fù)代碼。

3、靈活性:

可以動(dòng)態(tài)地添加或移除切面,而不需要修改核心業(yè)務(wù)代碼。

AOP 的缺點(diǎn)

1、學(xué)習(xí)曲線:

對于初學(xué)者來說,AOP 的概念和實(shí)現(xiàn)方式可能較難理解。

2、調(diào)試?yán)щy:

由于切面邏輯是動(dòng)態(tài)插入的,調(diào)試時(shí)可能難以追蹤問題。

3、性能開銷:

動(dòng)態(tài)代理和運(yùn)行時(shí)織入可能帶來一定的性能開銷。

AOP 的實(shí)現(xiàn)框架

1、Spring AOP:

Spring 框架提供的 AOP 實(shí)現(xiàn),基于動(dòng)態(tài)代理,易于與 Spring 集成。

2、AspectJ:

功能強(qiáng)大的 AOP 框架,支持編譯時(shí)織入和運(yùn)行時(shí)織入。

3、JBoss AOP:

JBoss 提供的 AOP 實(shí)現(xiàn),支持復(fù)雜的切面邏輯。

代碼實(shí)戰(zhàn)

  • maven依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>spring-boot-demo-log-aop</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-boot-demo-log-aop</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>com.xiaoma</groupId>
		<artifactId>spring-boot-demo</artifactId>
		<version>1.0.0-SNAPSHOT</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
		</dependency>

		<!-- 解析 UserAgent 信息 -->
		<dependency>
			<groupId>eu.bitwalker</groupId>
			<artifactId>UserAgentUtils</artifactId>
		</dependency>
	</dependencies>

	<build>
		<finalName>spring-boot-demo-log-aop</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
  • AopLog.java
@Aspect
@Component
@Slf4j
public class AopLog {
	private static final String START_TIME = "request-start";

	/**
	 * 切入點(diǎn)
	 */
	@Pointcut("execution(public * com.xiaoma.log.aop.controller.*Controller.*(..))")
	public void log() {

	}

	/**
	 * 前置操作
	 *
	 * @param point 切入點(diǎn)
	 */
	@Before("log()")
	public void beforeLog(JoinPoint point) {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

		HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

		log.info("【請求 URL】:{}", request.getRequestURL());
		log.info("【請求 IP】:{}", request.getRemoteAddr());
		log.info("【請求類名】:{},【請求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());

		Map<String, String[]> parameterMap = request.getParameterMap();
		log.info("【請求參數(shù)】:{},", JSONUtil.toJsonStr(parameterMap));
		Long start = System.currentTimeMillis();
		request.setAttribute(START_TIME, start);
	}

	/**
	 * 環(huán)繞操作
	 *
	 * @param point 切入點(diǎn)
	 * @return 原方法返回值
	 * @throws Throwable 異常信息
	 */
	@Around("log()")
	public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
		Object result = point.proceed();
		log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
		return result;
	}

	/**
	 * 后置操作
	 */
	@AfterReturning("log()")
	public void afterReturning() {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

		Long start = (Long) request.getAttribute(START_TIME);
		Long end = System.currentTimeMillis();
		log.info("【請求耗時(shí)】:{}毫秒", end - start);

		String header = request.getHeader("User-Agent");
		UserAgent userAgent = UserAgent.parseUserAgentString(header);
		log.info("【瀏覽器類型】:{},【操作系統(tǒng)】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header);
	}
}
  • TestController.java
@RestController
public class TestController {

	/**
	 * 測試方法
	 *
	 * @param who 測試參數(shù)
	 * @return {@link Dict}
	 */
	@GetMapping("/test")
	public Dict test(String who) {
		return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who);
	}

}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論

怀化市| 玉田县| 临澧县| 余姚市| 蒙山县| 济阳县| 东至县| 内乡县| 黄梅县| 若尔盖县| 安化县| 曲阜市| 宝鸡市| 自治县| 兴海县| 裕民县| 巍山| 中阳县| 克什克腾旗| 芜湖市| 清丰县| 儋州市| 平凉市| 新龙县| 广德县| 达日县| 麻城市| 壶关县| 东乌珠穆沁旗| 嘉兴市| 宜兴市| 张北县| 沅江市| 印江| 定边县| 凤冈县| 衢州市| 西昌市| 繁峙县| 昌都县| 曲阜市|