Spring學習(穀粒學院spring4課程)第六節 AOP
阿新 • • 發佈:2018-12-13
一:採用AOP的原因
程式碼混亂:越來越多的非業務需求(日誌和驗證等)加入後, 原有的業務方法急劇膨脹. 每個方法在處理核心邏輯的同時還必須兼顧其他多個關注點.
程式碼分散: 以日誌需求為例, 只是為了滿足這個單一需求, 就不得不在多個模組(方法)裡多次重複相同的日誌程式碼. 如果日誌需求發生變化, 必須修改所有模組.
二:基於aspectj註解宣告切面
例項:定義一個bean,為其新增日誌
(1)定義一個bean
import org.springframework.stereotype.Component; @Component public class Student { private String name; public void setName(String name) { this.name = name; } public int study(int i,int j) { // TODO Auto-generated method stub System.out.println("good study"); return i/j; } }
(2)建立切面及通知
package com.wh.spring.impl; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; 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.springframework.core.annotation.Order; import org.springframework.stereotype.Component; //把這個類宣告為一個切面,需要把該類放入到IOC容器中,再宣告為一個切面 //使用@Order指定切面的優先順序,數值越小,優先順序越高 @Aspect @Order(1) @Component public class LoggingAspect { //定義一個方法,用於宣告切入點表示式,一般該方法不需要填入其他程式碼 //使用@Pointcut宣告切入點表示式 //其他通知引用方法名引入該切入點 @Pointcut("execution(* com.wh.spring.aop.Student.*(..))") public void declareJointPointExpression() { } //宣告該方法是一個前置通知 //spring..表示com.wh.spring包及其子包 @Before("declareJointPointExpression()") public void beforeMethord(JoinPoint joinPoint) { String methordName=joinPoint.getSignature().getName(); List<Object> args=Arrays.asList(joinPoint.getArgs()); System.out.println("the methord before "+methordName+" "+args); } //後置通知:在目標方法執行後(無論是否發生異常),執行的通知 //後置通知中不能訪問目標方法的執行結果 @After("declareJointPointExpression()") public void afterMethord(JoinPoint joinPoint) { String methordName=joinPoint.getSignature().getName(); System.out.println("The methord "+methordName+" ends"); } //返回通知,方法正常結束後執行的程式碼 //返回通知是可以訪問到方法的返回值 @AfterReturning(value="declareJointPointExpression()", returning="result") public void afterReturning(JoinPoint joinPoint,Object result) { String methordName=joinPoint.getSignature().getName(); System.out.println("The methord "+methordName+" ends with "+result); } //在目標方法出現異常時會執行該程式碼,可以訪問到異常物件,且可以指定在出現指定異常時才執行通知程式碼 //指定ex的型別 @AfterThrowing(value="declareJointPointExpression()", throwing="ex") public void afterThrowing(JoinPoint joinPoint,Exception ex) { String methordName=joinPoint.getSignature().getName(); System.out.println("The methord "+methordName+" throw "+ex); } //環繞通知需要攜帶ProceedingJoinPoint型別的引數 //環繞通知類似於動態代理的全過程:ProceedingJoinPoint型別的引數可以決定是否執行目標方法,且環繞通知必須有返回值 //返回值即為目標方法的返回值 //不常用環繞通知 @Around("declareJointPointExpression()") public Object aroundMethord(ProceedingJoinPoint pjd) { System.out.println("aroundMethord"); Object result=null; String methordName=pjd.getSignature().getName(); //執行目標方法 try { //前置通知 System.out.println(methordName+" begins with "+Arrays.asList(pjd.getArgs())); result=pjd.proceed(); //返回通知 System.out.println(methordName+" ends with "+result); } catch (Throwable e) { // 異常通知 System.out.println("發生異常:"+e); } // 後置通知 System.out.println("the methord "+methordName+" ends with around"); return 100; } }
(3)使aspectj註解起作用,自動為匹配的類生成代理物件
在spring配置檔案中加入
<!-- 使aspectj註解起作用,自動為匹配的類生成代理物件 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
三:基於配置檔案的AOP
(1)配置切面bean
<!-- 配置切面的bean-->
<bean id="loggingAspect" class="com.wh.spring.xml.LoggingAspect"></bean>
(2)配置切點,切面及通知
<aop:config>
<!-- 配置切點表示式 -->
<aop:pointcut expression="execution(* com.wh.spring.xml.Student.*(..))" id="pointcut"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="0">
<aop:before method="beforeMethord" pointcut-ref="pointcut"/>
<aop:after method="afterMethord" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<aop:around method="aroundMethord" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
四:其他
(1)切面的順序由@Order(1)或order="0"指定,數字越小,優先順序越高
(2)切點的重用
//定義一個方法,用於宣告切入點表示式,一般該方法不需要填入其他程式碼
//使用@Pointcut宣告切入點表示式
//其他通知引用方法名引入該切入點
@Pointcut("execution(* com.wh.spring.aop.Student.*(..))")
public void declareJointPointExpression() {
}