Spring框架--AOP
阿新 • • 發佈:2017-09-23
aspectj 分享 org avi ng- lns owin 支持 .org
1、AOP (面向切面編程)
AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程
通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術
AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型
利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率
AOP 思想:橫向重復、縱向抽取
2、底層實現: Spring 的 AOP 的底層用到兩種代理機制:
JDK 的動態代理:針對實現了接口的類產生代理
Cglib 的動態代理:針對沒有實現接口的類產生代理,應用的是底層的字節碼增強的技術 生成當前類的子類對象
3、AOP 的開發中的相關術語:
Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在 spring 中,這些點指的是方法,因為 spring 只支持方法類型的連接點(可以被切入的點)
Pointcut(切入點):所謂切入點是指我們要對哪些 Joinpoint 進行攔截的定義。(已經被切入的點)
Advice(通知/增強):所謂通知是指攔截到 Joinpoint 之後所要做的事情就是通知。通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下,Introduction 可以在運行期為類動態地添加一些方法或 Field。
Aspect(切面):是切入點和通知(引介)的結合
Target(目標對象):代理的目標對象
Proxy(代理):一個類被 AOP 織入增強後,就產生一個結果代理類。
Weaving(織入):是指把增強應用到目標對象來創建新的代理對象的過程。spring 采用動態代理織入,而 AspectJ 采用編譯期織入和類裝載期織入。
4、 示例的項目結構:
4.1使用XML配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 目標對象 --> <bean name="userService" class="com.roxy.spring.service.UserServiceImpl"></bean> <!-- 通知對象 --> <bean name="transactionAdvice" class="com.roxy.spring.advice.TransactionAdvice"></bean> <!-- 將通知對象織入目標對象 --> <aop:config> <!-- 選擇切入點 --> <aop:pointcut expression="execution(* com.roxy.spring.service..*ServiceImpl.*(..))" id="pointcut"/> <!-- 選擇切入時機 --> <aop:aspect ref="transactionAdvice"> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/><!-- 無論是否出現異常都會調用 --> <!--<aop:around method="around" pointcut-ref="pointcut"/> <aop:after-throwing method="afterException" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>
public interface UserService { public void save(); public void delete(); public void update(); public void select(); }
public class UserServiceImpl implements UserService{ @Override public void save() { System.out.println("保存用戶"); } @Override public void delete() { System.out.println("刪除用戶"); } @Override public void update() { System.out.println("更新用戶"); } @Override public void select() { System.out.println("查詢用戶"); } }
public class TransactionAdvice { public void before() { System.out.println("前置通知被執行"); } public void afterReturning() { System.out.println("後置通知被執行(出現異常不調用)"); } public void after() { System.out.println("後置通知被執行(無論是否出現異常都會調用)"); } public void afterException() { System.out.println("異常通知被執行"); } public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("around_before"); Object proceed = point.proceed();//調用目標方法 System.out.println("around_after"); return proceed; } }
4.2 使用註解
<!-- 目標對象 --> <bean name="userService" class="com.roxy.spring.service.UserServiceImpl"></bean> <!-- 通知對象 --> <bean name="transactionAdvice" class="com.roxy.spring.advice.TransactionAdvice"></bean> <!-- 開啟織入註解 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Aspect //該類為切面 public class TransactionAdvice { @Pointcut(value="execution(* com.roxy.spring.service..*ServiceImpl.*(..))") public void PointCut(){} @Before("TransactionAdvice.PointCut()") public void before() { System.out.println("前置通知被執行"); } @AfterReturning("TransactionAdvice.PointCut()") public void afterReturning() { System.out.println("後置通知被執行(出現異常不調用)"); } @After("TransactionAdvice.PointCut()") public void after() { System.out.println("後置通知被執行(無論是否出現異常都會調用)"); } @AfterThrowing("TransactionAdvice.PointCut()") public void afterException() { System.out.println("異常通知被執行"); } @Around("TransactionAdvice.PointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("around_before"); Object proceed = point.proceed();//調用目標方法 System.out.println("around_after"); return proceed; } }
5、5種通知的調用順序
console:
around_before
前置通知被執行
保存用戶
around_after
後置通知被執行(無論是否出現異常都會調用)
後置通知被執行(出現異常不調用)
result:
環繞通知 --> 前置通知 --> 調用方法 --> 環繞通知 --> 後置通知(after) --> 後置通知(afterException)
6、AOP中的正則表達式
aop配置切點的正則表達式 . 匹配除換行外的所有單個字符 * 匹配前面的字符0次或多次 + 匹配前面的字符1次或多次 ? 匹配前面的字符0次或1次 ^ 匹配字符串開始 $ 匹配字符串結束 x|y 匹配x或y [xyz] zyx其中一個 {n} 匹配n次 {n,} 匹配至少n次 {n,m} 匹配n次到m次 \ 轉意字符
Spring框架--AOP