《Java Spring框架》Spring切面(AOP)配置詳解
阿新 • • 發佈:2019-12-21
1. Spring 基本概念
AOP(Aspect Oriented Programming)稱為面向切面程式設計,在程式開發中主要用來解決一些系統層面上的問題,比如日誌,事務,許可權等待,Struts2的攔截器設計就是基於AOP的思想,是個比較經典的例子。
在不改變原有的邏輯的基礎上,增加一些額外的功能。代理也是這個功能,讀寫分離也能用aop來做。
2. 原理圖:
我們希望業務開發人員只關心中間部分,不再需要關係開啟和關閉資料庫連線的情況,同時也避免了程式碼重複和可能出現的問題。
3. 程式碼
public interface UserService { //刪 void save(); String getStr(); void setStr(String str); }
public class UserServiceImpl implements UserService { private String str = "0"; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public void save() { System.out.println("--------- save --------------"); } }
import org.aspectj.lang.ProceedingJoinPoint; /** * 自定義通知類 */ public class MyAdvice { //before 前置通知 在目標方法前呼叫 public void before() { System.out.println("before"); } //after 最終通知(後置通知)在目標方法後呼叫,無論是否出現異常都會執行 finally public void after() { System.out.println("after"); } //afterReturning 成功通知(後置通知)在目標方法執行後,並且執行成功,如果方法出現異常則不呼叫 public void afterReturning() { System.out.println("afterReturning"); } //afterThrowing 異常通知(後置通知)在目標方法執行出現異常的時候才會呼叫 public void afterThrowing() { System.out.println("afterThrowing"); } //around 環繞通知 需要我們手動呼叫目標方法,並且可以設定通知 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before"); Object proceed = pjp.proceed(); System.out.println("around after"); return proceed; } }
import com.bing.aop.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext_aop.xml") public class AopTest { @Resource(name="userService") UserService us; @Test public void Test2() { us.save(); } }
配置檔案:檔名(applicationContext_aop.xml)
<?xml version="1.0" encoding="UTF-8"?> <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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 目標物件 --> <bean name="userService" class="com.bing.aop.service.UserServiceImpl"></bean> <!-- 通知物件 --> <bean name="myAdvice" class="com.bing.aop.MyAdvice"></bean> <aop:config> <!-- 切入點 expression 切入點表示式 可以配置要增強的方法 public void com.bing.aop.service.UserServiceImpl.save() * com.bing.aop.service.*ServiceImpl.*(..) id 就是唯一標識 --> <aop:pointcut expression="execution(* com.bing.aop.service.*ServiceImpl.*(..))" id="servicePc"/> <!-- 切面 通知+切入點 --> <aop:aspect ref="myAdvice"> <!-- 通知型別 --> <aop:before method="before" pointcut-ref="servicePc"/> <!-- 最終通知 後置通知 --> <aop:after method="after" pointcut-ref="servicePc"/> <!-- 成功通知 後置通知 --> <aop:after-returning method="afterReturning" pointcut-ref="servicePc"/> <!-- 異常通知 後置通知 --> <aop:after-throwing method="afterThrowing" pointcut-ref="servicePc"/> <!-- 環繞通知--> <aop:around method="around" pointcut-ref="servicePc"/> </aop:aspect> </aop:config> </beans>
執行結果:
到這裡其實發現這個AOP沒有什麼實際用處,前後中間執行的東西都沒有關係,並不能體現真正的AOP思想。
我們將上述程式碼修改一下:修改環繞通知的方法。
import com.bing.aop.service.UserService; import com.bing.aop.service.UserServiceImpl; import org.aspectj.lang.ProceedingJoinPoint; /** * 自定義通知類 */ public class MyAdvice { //before 前置通知 在目標方法前呼叫 public void before() { System.out.println("before"); } //after 最終通知(後置通知)在目標方法後呼叫,無論是否出現異常都會執行 finally public void after() { System.out.println("after"); } //afterReturning 成功通知(後置通知)在目標方法執行後,並且執行成功,如果方法出現異常則不呼叫 public void afterReturning() { System.out.println("afterReturning"); } //afterThrowing 異常通知(後置通知)在目標方法執行出現異常的時候才會呼叫 public void afterThrowing() { System.out.println("afterThrowing"); } //around 環繞通知 需要我們手動呼叫目標方法,並且可以設定通知 public Object around(ProceedingJoinPoint pjp) throws Throwable { UserService userService = (UserServiceImpl)pjp.getTarget(); Object proceed = null; if("1".equals(userService.getStr()) || "setStr".equals(pjp.getSignature().getName())){ proceed = pjp.proceed(); } return proceed; } }
import com.bing.aop.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext_aop.xml") public class AopTest { @Resource(name="userService") UserService us; @Test public void Test2() { System.out.println("設定前:------------Str == 0"); us.save(); us.setStr("1"); System.out.println("設定前:------------Str == 1"); us.save(); } }
然後將配置檔案的其他通知都去掉:
<?xml version="1.0" encoding="UTF-8"?> <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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 目標物件 --> <bean name="userService" class="com.bing.aop.service.UserServiceImpl"></bean> <!-- 通知物件 --> <bean name="myAdvice" class="com.bing.aop.MyAdvice"></bean> <aop:config> <!-- 切入點 expression 切入點表示式 可以配置要增強的方法 public void com.bing.aop.service.UserServiceImpl.save() * com.bing.aop.service.*ServiceImpl.*(..) id 就是唯一標識 --> <aop:pointcut expression="execution(* com.bing.aop.service.*ServiceImpl.*(..))" id="servicePc"/> <!-- 切面 通知+切入點 --> <aop:aspect ref="myAdvice"> <!-- 環繞通知--> <aop:around method="around" pointcut-ref="servicePc"/> </aop:aspect> </aop:config> </beans>
執行效果:
把實體類和MyAdvice 結合起來,可以更加方便的寫你想要處理的邏輯。
不喜歡誇誇奇談,實戰才是真理。程式碼是說明原理的最可靠的方式。
總結來源:http://www.sikiedu.com/ 網站學習