意爲面向切面編程,把咱們程序重複的代碼抽取出來,在須要執行的時候,使用動態代理的技術,在不修改源碼的基礎上,對咱們已有方法進行加強java
==使用動態代理技術==spring
步驟:express
使用aop:aspect標籤代表配置切面編程
在aop:aspect標籤的內部使用對應標籤來配置通知的類型框架
配置切入點表達式 代理
id屬性用於指定表達式的惟一標識。expression屬性用於指定表達式內容code
此標籤寫在aop:aspect標籤內部只能當前切面使用。xml
它還能夠寫在aop:aspect外面,此時就變成了全部切面可用接口
<aop:pointcut id="pt1" expression="execution(* com.ming.service.impl.*.*(..))"></aop:pointcut>
<!-- 配置前置通知:在切入點方法執行以前執行--> <aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before> <!-- 配置後置通知:在切入點方法正常執行以後值。它和異常通知永遠只能執行一個--> <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning> <!-- 配置異常通知:在切入點方法執行產生異常以後執行。它和後置通知永遠只能執行一個--> <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing> <!-- 配置最終通知:不管切入點方法是否正常執行它都會在其後面執行--> <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
<!-- 配置環繞通知--> <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around> 問題: 當咱們配置了環繞通知以後,切入點方法沒有執行,而通知方法執行了。 分析: 經過對比動態代理中的環繞通知代碼,發現動態代理的環繞通知有明確的切入點方法調用,而咱們的代碼中沒有。 解決: Spring框架爲咱們提供了一個接口:ProceedingJoinPoint。該接口有一個方法proceed(),此方法就至關於明確調用切入點方法。該接口能夠做爲環繞通知的方法參數,在程序執行時,spring框架會爲咱們提供該接口的實現類供咱們使用。 spring中的環繞通知: 它是spring框架爲咱們提供的一種能夠在代碼中手動控制加強方法什麼時候執行的方式。 案例演示(利用ProceedingJoinPoint接口): public Object aroundPringLog(ProceedingJoinPoint pjp){ Object rtValue = null; try{ Object[] args = pjp.getArgs();//獲得方法執行所需的參數 System.out.println("前置"); rtValue = pjp.proceed(args);//明確調用業務層方法(切入點方法) System.out.println("後置"); return rtValue; }catch (Throwable t){ System.out.println("異常"); throw new RuntimeException(t); }finally { System.out.println("最終"); } }
==切入點表達式的寫法:==開發
關鍵字:execution(表達式) 表達式: 訪問修飾符 返回值 包名.包名.包名...類名.方法名(參數列表) 標準的表達式寫法: public void com.ming.service.impl.AccountServiceImpl.saveAccount() 訪問修飾符能夠省略 void com.ming.service.impl.AccountServiceImpl.saveAccount() 返回值可使用通配符,表示任意返回值 * com.ming.service.impl.AccountServiceImpl.saveAccount() 包名可使用通配符,表示任意包。可是有幾級包,就須要寫幾個 *.* *.*.*.*.AccountServiceImpl.saveAccount()) 包名可使用..表示當前包及其子包 * *..AccountServiceImpl.saveAccount() 類名和方法名均可以使用*來實現通配 * *..*.*() 參數列表: 能夠直接寫數據類型: 基本類型直接寫名稱 int 引用類型寫包名.類名的方式 java.lang.String 可使用通配符表示任意類型,可是必須有參數 可使用..表示有無參數都可,有參數能夠是任意類型 全通配寫法: * *..*.*(..) 實際開發中切入點表達式的一般寫法:切到業務層實現類下的全部方法 * com.ming.service.impl.*.*(..)
在bean.xml配置spring開啓註解AOP的支持
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
代表某個類爲切面類
@Aspect//表示當前類是一個切面類
在類的方法裏配置通知類型
@Pointcut("切入點表達式")//配置切入點表達式 private void pt1(){} @Before("pt1()")//前置通知 @AfterReturning("pt1()")//後置通知 @AfterThrowing("pt1()")//異常通知 @After("pt1()")//最終通知 @Around("pt1()")//環繞通知 //在通知類型中的方法須要加(),如pt1()