學(xué)習(xí)視頻:【編程不良人】2021年SpringBoot最新最全教程
第十一章、AOP
11.1 為什么要使用AOP
-
問題
- 現(xiàn)有業(yè)務(wù)層開發(fā)存在問題
- 額外功能代碼存在大量冗余
- 每個方法都需要書寫一遍額外功能代碼不利于項目維護(hù)
- 現(xiàn)有業(yè)務(wù)層開發(fā)存在問題
-
Spring中的AOP
AOP:Aspect 切面 + Oriented 面向 Programmaing 面向切面編程
Aspect(切面) = Advice(通知) + Pointcut(切入點)
Advice 通知:業(yè)務(wù)邏輯中的一些附加操作稱之通知
Pointcut 切入點:配置通知應(yīng)用于項目中那些業(yè)務(wù)操作
-
Advice通知就是附加操作的代碼,Advice通知類型都有不同的執(zhí)行策略和用途。
@Before 在目標(biāo)方法執(zhí)行之前執(zhí)行的通知。它不能阻止方法的執(zhí)行,但可以在方法執(zhí)行前添加額外的功能。 @AfterReturning 在目標(biāo)方法正常返回后執(zhí)行的通知。例如,如果一個方法正常返回而沒有拋出異常,就會執(zhí)行這個通知。 @AfterThrowing 在目標(biāo)方法拋出異常后執(zhí)行的通知。如果一個方法拋出異常,就會執(zhí)行這個通知。 @After 在目標(biāo)方法執(zhí)行之后執(zhí)行的通知。無論目標(biāo)方法如何退出(正常返回或拋出異常),都會執(zhí)行的通知。 @Around 包圍目標(biāo)方法的通知,可以在目標(biāo)方法執(zhí)行前后添加額外的功能,并決定是否繼續(xù)執(zhí)行目標(biāo)方法。 -
Pointcut 是切入點,決定了Advice加在哪個具體方法代碼上,具體使用方式:
1.切入點直接寫在附加操作里面 @Around(value="execution(* login(..))") 2.通過@Pointcut注解 聲明切入點,實現(xiàn)復(fù)用 @Pointcut("execution(* login(..))") // 復(fù)用切入點,解耦合 public void myPointcut(){} @Around("myPointcut()") @After("myPointcut()") @Before("myPointcut()")
11.2 AOP的實現(xiàn)
-
引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
目前UserServiceImp存在的問題
以log日志這種額外功能為例,這樣的重復(fù)操作存在冗余代碼和耦合
@Service public class UserServiceImpl implements UserService { @Override public void save(String name) { System.out.println("========log========"); System.out.println("UserServiceImpl.save"); } @Override public void delete(Integer id) { System.out.println("========log========"); System.out.println("UserServiceImpl.delete"); } @Override public void update(String name) { System.out.println("========log========"); System.out.println("UserServiceImpl.update"); } @Override public String find(String name) { System.out.println("========log========"); System.out.println("UserServiceImpl.find"); return "name"; } }
-
我們通過一個切面配置類來解耦合
/** * 自定義切面配置類 */ @Configuration // 指定當(dāng)前類為配置類 @Aspect // 代表這個類是一個切面配置類 public class MyAspectConfig { @Before("execution(* com.example.service.*.*(..))") // @Before代表在業(yè)務(wù)邏輯執(zhí)行前運(yùn)行 value代表切入點 public void before() { System.out.println(" =====前置附加操作:log====== "); } }
-
通過切入點,完成整個業(yè)務(wù)的額外功能覆蓋,運(yùn)行效果
11.3 JoinPoint 參數(shù)詳解
JoinPoint
參數(shù)可以在通知體內(nèi)聲明,用于獲取有關(guān)方法執(zhí)行的信息。JoinPoint
參數(shù)提供了許多有用的方法,例如getSignature()
可以獲取方法的簽名,getArgs()
可以獲取方法的參數(shù)列表,getTarget()
可以獲取目標(biāo)對象等。通過JoinPoint
參數(shù),我們可以在通知中訪問和操作方法執(zhí)行時的上下文信息。
JoinPoint
參數(shù)通常用于以下幾種情況:
- 記錄日志:獲取方法的簽名和參數(shù)列表,從而記錄方法的執(zhí)行情況,包括方法名、參數(shù)值等。
- 異常處理:獲取方法執(zhí)行時拋出的異常信息,從而進(jìn)行相應(yīng)的異常處理。
- 性能監(jiān)控:獲取方法的執(zhí)行時間、參數(shù)值等信息,用于性能監(jiān)控和優(yōu)化。
獲取執(zhí)行方法的信息
@Before("execution(* com.example.service.*.*(..))") //
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getName();
Object[] args = joinPoint.getArgs();
System.out.println("Before 執(zhí)行方法: " + methodName + " 在類:" + className);
System.out.println("方法參數(shù) = " + Arrays.toString(args));
}
11.4 @Around 環(huán)繞附加操作
使用@Around注解的方法,參數(shù)必須聲明ProceedingJoinPoint
,這個參數(shù)可以控制目標(biāo)方法的執(zhí)行
@Around("execution(* com.example.service.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("======進(jìn)入環(huán)繞的前置操作======");
System.out.println("當(dāng)前執(zhí)行類 = " + pjp.getSignature().getName());
System.out.println("方法名 = " + pjp.getTarget().getClass().getSimpleName());
//放行目標(biāo)方法執(zhí)行
Object proceed = pjp.proceed(); // 目標(biāo)方法繼續(xù)執(zhí)行
System.out.println(" =====進(jìn)入環(huán)繞的后置操作========= ");
return proceed;
}
-
運(yùn)行效果
11.5 自定義注解方式的切入點表達(dá)式@annotation
通過自定義注解@annotation
實現(xiàn)切面的好處在于可以使切面的定義更加靈活和可重用。使用自定義注解可以將切面的邏輯和配置信息封裝在注解中,使得切面的使用和配置變得更加簡單和直觀。
-
MyAdvice 自定義注解
@Retention(RetentionPolicy.RUNTIME) // 指定運(yùn)行時保留 @Target(ElementType.METHOD) //指定修飾 方法 public @interface MyAdvice { }
-
放在通知里的@annotation屬性使用,代表只有被
@MyAdvice
修飾的方法才會被加入額外功能**@Around("@annotation(com.example.config.MyAdvice)")** public Object around(ProceedingJoinPoint pjp) throws Throwable { }
-
通過將注解加在業(yè)務(wù)邏輯上,實現(xiàn)給目標(biāo)方法加上額外功能的目的文章來源:http://www.zghlxwxcb.cn/news/detail-760253.html
UserServiceImpl @Override @MyAdvice public String find(String name) { // System.out.println("========log========"); System.out.println("UserServiceImpl.find"); return "name"; }
下一章:Spring Boot學(xué)習(xí)隨筆- 文件上傳和下載(在線打卡、附件下載、MultipartFile)文章來源地址http://www.zghlxwxcb.cn/news/detail-760253.html
到了這里,關(guān)于Spring Boot學(xué)習(xí)隨筆- 實現(xiàn)AOP(JoinPoint、ProceedingJoinPoint、自定義注解類實現(xiàn)切面)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!