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