AOP在spring中是非常重要的一個
在切面類中,有5種通知類型:
aop:before 前置通知
aop:after-returning 後置通知
aop:after 最終通知
aop:after-throwing 異常通知
aop:around 環繞通知
1 <bean id="personDAO" class="com.lee.spring002.aop.xml.PersonDAOImpl"></bean> 2 <bean id="transaction" class="com.lee.spring002.aop.xml.Transaction"></bean> 3 4 <aop:config > 5 <!-- 切入點表達式,作用:確定目標類 --> 6 <!-- spring 會自動檢測這個表達式下的類是否是切面,如果是,則不會包含進來 --> 7 <aop:pointcut expression="execution(* com.lee.spring002.aop.xml.PersonDAOImpl.*(..))" id="perform"/> 8 <!-- ref 指向切面 --> 9 <aop:aspect ref="transaction"> 10 <!-- 前置通知 --> 11 <aop:before method="beginTransaction" pointcut-ref="perform"/> 12 13 <!-- 14 後置通知 15 可以獲取目標方法的返回值(前置方法獲取不到) 16 如果目標方法拋出異常,後置通知則不會繼續執行 17 --> 18 <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/> 19 20 <!-- 21 最終通知 22 無論目標方法是否拋出異常都將執行此方法 23 --> 24 <aop:after method="finallyDisplay" pointcut-ref="perform"/> 25 26 <!-- 27 異常通知 28 --> 29 <aop:after-throwing method="exception" pointcut-ref="perform" throwing="content"/> 30 31 <!-- 32 環繞通知 33 能控制目標方法能否執行 34 前置通知和後置通知能在目標方法的前後加代碼,但是不能控制方法的執行 35 --> 36 <aop:around method="arround" pointcut-ref="perform"/> 37 </aop:aspect> 38 </aop:config>
關於切面的表達式簡單說一下:
execution(public * *(..))
execution(* set*(..))
AccountService
接口定義的任意方法的執行:
execution(* com.xyz.service.AccountService.*(..))
execution(* com.xyz.service.*.*(..))
execution(* com.xyz.service..*.*(..))
IPersonDAO.java
1 package com.lee.spring002.aop.xml; 2 3 public interface IPersonDAO { 4 public String savePerson(); 5 }
PersonDAOImpl.java
1 package com.lee.spring002.aop.xml; 2 3 public class PersonDAOImpl implements IPersonDAO { 4 5 @Override 6 public String savePerson() { 7 System.out.println("PersonDAOImpl - savePerson()"); 8 9 // int a = 1 / 0; 10 11 return "save successfully"; 12 } 13 14 }
Transaction.java
1 package com.lee.spring002.aop.xml; 2 3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 6 /** 7 * 這是個切面 8 * 9 * @author leechenxiang 10 * @date 2016年1月12日 11 * 12 */ 13 public class Transaction { 14 15 public void beginTransaction(JoinPoint jp) { 16 System.out.println("連接點名稱: " + jp.getSignature().getName()); 17 System.out.println("目標類名稱: " + jp.getTarget().getClass()); 18 System.out.println("Begin transaction..."); 19 } 20 21 /** 22 * 23 * @param jp 24 * @param val 目標方法返回值,要與returning對應 25 */ 26 public void commit(JoinPoint jp, Object val) { 27 System.out.println("Transaction commit..."); 28 29 System.out.println("returning: " + val.toString()); 30 } 31 32 public void finallyDisplay() { 33 System.out.println("finally..."); 34 } 35 36 public void exception(JoinPoint jp, Throwable content) { 37 System.out.println("exception: " + content); 38 System.out.println("exception: " + content.getMessage()); 39 } 40 41 public void arround(ProceedingJoinPoint pjp) throws Throwable { 42 System.out.println("arround..."); 43 pjp.proceed(); // 調用目標方法,如果這行不寫,則目標方法不執行 44 } 45 }
測試:
1 package com.lee.spring002.aop.xml; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class TransactionTest { 8 9 /** 10 * 原理: 11 * 1、當spring容器啟動的時候,加載兩個bean,對兩個bean進行實例化 12 * 2、當spring容器對配置文件解析到<aop:config>的時候 13 * 3、把切入點表達式解析出來,按照切入點表達式匹配spring容器內容的bean 14 * 4、如果匹配成功,則為該bean創建代理對象 15 * 5、當客戶端利用context.getBean獲取一個對象時,如果該對象有代理對象,則返回代理對象 16 * 如果沒有代理對象,則返回對象本身 17 */ 18 @Test 19 public void testPerson() { 20 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 21 IPersonDAO personDAO = (IPersonDAO)context.getBean("personDAO"); 22 personDAO.savePerson(); 23 } 24 25 }
github地址:https://github.com/leechenxiang/maven-spring002-aop