學習材料
尚硅谷Spring零基礎入門到進階,一套搞定spring6全套視頻教程(源碼級講解)
AOP
AOP(Aspect Oriented Programming)是一種設計思想,是軟件設計領域中的面向切面編程,它是面向對象編程的一種補充和完善,它以通過預編譯方式和運行期動態代理方式實現,在不修改源代碼的情況下,給程序動態統一添加額外功能的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
需要了解相關的術語:
- 關注橫切面(分散在每個各個模塊中解決同一樣的問題,如用戶驗證、日志管理、事務處理、數據緩存都屬于橫切關注點。)
- 通知or增強
- 切面
- 目標(被代理的目標方法,對象)
- 代理(代理對象)
- 連接點
- 切入點:
定位連接點的方式。
每個類的方法中都包含多個連接點,所以連接點是類中客觀存在的事物(從邏輯上來說)。
如果把連接點看作數據庫中的記錄,那么切入點就是查詢記錄的 SQL 語句。
Spring 的 AOP 技術可以通過切入點定位到特定的連接點。通俗說,要實際去增強的方法
切點通過 org.springframework.aop.Pointcut 接口進行描述,它使用類和方法作為連接點的查詢條件。
AOP的作用
-
簡化代碼:把方法中固定位置的重復的代碼抽取出來,讓被抽取的方法更專注于自己的核心功能,提高內聚性。
-
代碼增強:把特定的功能封裝到切面類中,看哪里有需要,就往上套,被套用了切面邏輯的方法就被切面給增強了。
基于注解實現AOP
基于動態代理實現的,而動態代理分為JDK和cglib(jdk是在目標是實現類的情況下使用。)
具體內容還是要認真看課件,不是特別明白
動手嘗試
引入依賴:pom.xml
<!--spring aop依賴--><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.2</version></dependency><!--spring aspects依賴--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version></dependency>
bean.xml配置
<!--基于注解的AOP的實現:1、將目標對象和切面交給IOC容器管理(注解+掃描)2、開啟AspectJ的自動代理,為目標對象自動生成代理3、將切面類通過注解@Aspect標識--><context:component-scan base-package="com.atguigu.aop.annotation"></context:component-scan><aop:aspectj-autoproxy />
建立的環境就是很簡單一個Calculator接口,并實現加減乘除。我需要在每個實現方法的前后進行日志的輸出,這樣就需要解耦出來。
如何編寫切面類:最主要的是寫切入點表達式
// @Aspect表示這個類是一個切面類
@Aspect
// @Component注解保證這個切面類能夠放入IOC容器
@Component
public class LogAspect {@Before("execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..))")public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",參數:"+args);}@After("execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))")public void afterMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->后置通知,方法名:"+methodName);}@AfterReturning(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result")public void afterReturningMethod(JoinPoint joinPoint, Object result){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:"+methodName+",結果:"+result);}@AfterThrowing(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->異常通知,方法名:"+methodName+",異常:"+ex);}@Around("execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());Object result = null;try {System.out.println("環繞通知-->目標對象方法執行之前");//目標對象(連接點)方法的執行result = joinPoint.proceed();System.out.println("環繞通知-->目標對象方法返回值之后");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("環繞通知-->目標對象方法出現異常時");} finally {System.out.println("環繞通知-->目標對象方法執行完畢");}return result;}}
然后正常的調用想要調用的類就行。
基于xml實現AOP
<aop:config><!--配置切面類--><aop:aspect ref="loggerAspect"><aop:pointcut id="pointCut" expression="execution(* com.atguigu.aop.xml.CalculatorImpl.*(..))"/><aop:before method="beforeMethod" pointcut-ref="pointCut"></aop:before><aop:after method="afterMethod" pointcut-ref="pointCut"></aop:after><aop:after-returning method="afterReturningMethod" returning="result" pointcut-ref="pointCut"></aop:after-returning><aop:after-throwing method="afterThrowingMethod" throwing="ex" pointcut-ref="pointCut"></aop:after-throwing><aop:around method="aroundMethod" pointcut-ref="pointCut"></aop:around></aop:aspect>
</aop:config>