AOP基於xml配置方式實現
Spring基於xml開發AOP
- 定義目標類(接口及實現類)
1 /** 2 * 目標類 3 */ 4 public interface UserService { 5 //業務方法 6 public void getById(); 7 public void add(); 8 public void delete(); 9 public String update(); 10 public void batch(); 11 }
1 public class UserServiceImpl implements UserService { 2 @Override 3 public void getById() { 4 System.out.println("UserServiceImpl類的getById方法被調用..."); 5 //拋出異常 6 System.out.println(1/0); 7 } 8 @Override 9 public void add() { 10 System.out.println("UserServiceImpl類的add方法被調用..."); 11 } 12 @Override 13 public void delete() { 14 System.out.println("UserServiceImpl類的delete方法被調用..."); 15 // System.out.println(1/0); 16 } 17 @Override 18 public String update() { 19 System.out.println("UserServiceImpl類的update方法被調用..."); 20 // System.out.println(1/0); 21 return "update的返回值"; 22 } 23 @Override 24 public void batch() { 25 System.out.println("UserServiceImpl類的batch方法被調用..."); 26 } 27 }
- 定義切面類
1 /** 2 * 切面 3 */ 4 public class UserAspect { 5 //前置通知 6 public void beforeAdvice(JoinPoint jp){ 7 //獲取切入點的方法的名稱 8 String name = jp.getSignature().getName(); 9 System.out.println("前置通知切入點的方法的名稱:"+name); 10 System.out.println("前置通知"); 11 } 12 13 //後置通知 14 public void afterAdvice(JoinPoint jp){ 15 //獲取切入點的方法的名稱 16 String name = jp.getSignature().getName(); 17 System.out.println("後置通知切入點的方法的名稱:"+name); 18 System.out.println("後置通知"); 19 } 20 21 //返回通知 22 //可以獲取object類型的返回值 23 //注意:result名稱必須和配置文件中的returning的名稱保持一致 24 public void afterReturningAdvice(JoinPoint jp,Object result){ 25 //獲取切入點的方法的名稱 26 String name = jp.getSignature().getName(); 27 System.out.println("返回通知切入點的方法的名稱:"+name); 28 //打印返回值 29 System.out.println(result); 30 System.out.println("返回通知"); 31 } 32 33 //異常通知 34 public void exceptionAdvice(JoinPoint jp,Exception ex){ 35 //獲取切入點的方法的名稱 36 String name = jp.getSignature().getName(); 37 System.out.println("異常通知切入點的方法的名稱:"+name); 38 //打印異常信息 39 System.out.println(ex.getMessage()); 40 System.out.println("異常通知"); 41 } 42 43 //環繞通知 44 //必須有一個參數:ProceedingJoinPoint 45 //有返回值:Object 46 public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ 47 System.out.println("環繞通知前"); 48 //執行業務邏輯方法 49 Object result = pjp.proceed(); 50 //獲取切入點的方法的名稱 51 String name = pjp.getSignature().getName(); 52 System.out.println("環繞通知切入點的方法的名稱:"+name); 53 System.out.println("環繞通知後"); 54 return result; 55 } 56 }
- 配置spring核心配置文件
<?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.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- 把切面和業務對象放到容器中 --> <bean id="userAspect" class="spring.aop.xml.UserAspect"></bean> <bean id="userServiceImpl" class="spring.aop.xml.UserServiceImpl"></bean> <!-- 配置aop的實現 --> <aop:config> <!-- 切入點的配置 expression(切入點表達式):指定切哪個方法 --> <aop:pointcut expression="execution(* *.add*(..))" id="pointCut01"/> <aop:pointcut expression="execution(* *.delete*(..))" id="pointCut02"/> <aop:pointcut expression="execution(* *.update*(..))" id="pointCut03"/> <aop:pointcut expression="execution(* *.getById*(..))" id="pointCut04"/> <aop:pointcut expression="execution(* *.batch*(..))" id="pointCut05"/> <!-- 切面的配置 --> <aop:aspect ref="userAspect"> <!-- 前置通知的配置:在pointCut01切入點的位置添加beforeAdvice的通知 --> <aop:before method="beforeAdvice" pointcut-ref="pointCut01"/> <!-- 後置通知的配置:在pointCut02切入點的位置添加afterAdvice的通知 --> <aop:after method="afterAdvice" pointcut-ref="pointCut02"/> <!-- 返回通知的配置:在pointCut03切入點的位置添加afterReturningAdvice的通知 returning:返回值的參數名稱 --> <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointCut03" returning="result"/> <!-- 異常通知的配置:在pointCut04切入點的位置添加exceptionAdvice的通知 throwing:拋出異常的名稱,必須和通知上的形參名稱一致 --> <aop:after-throwing method="exceptionAdvice" pointcut-ref="pointCut04" throwing="ex"/> <!-- 環繞通知的配置:在pointCut05切入點的位置添加aroundAdvice的通知 --> <aop:around method="aroundAdvice" pointcut-ref="pointCut05"/> </aop:aspect> </aop:config> </beans>
- 測試
1 //使用xml方式配置AOP 2 @RunWith(SpringJUnit4ClassRunner.class) 3 @ContextConfiguration("classpath:applicationContext-aop-xml.xml") 4 public class XmlAopTest { 5 //注入業務對象 6 @Autowired 7 private UserService userService; 8 9 //測試AOP,對切入點進行增強 10 @Test 11 public void test(){ 12 //前置通知的測試 13 // userService.add(); 14 15 //後置通知的測試(無論有沒有異常都會執行) 16 // userService.delete(); 17 18 //返回通知的測試(只有業務方法正常執行時,纔會執行的通知) 19 // userService.update(); 20 21 //異常通知的測試 22 // userService.getById(); 23 24 //環繞通知的測試 25 userService.batch(); 26 } 27 }
AOP的切入點表達式execution
表達式的寫法:修飾關鍵詞 返回值類型 包名.類名.方法名(..)
修飾關鍵詞:protected , public , private ….一般都省略不寫
返回值類型:一般返回值類型用 * 號代替,表示任意的返回值都可以
方法名中的兩個點:表示所帶的參數的個數。
舉例如下:
任意以public修飾的方法都可以 execution(public * *(..))
任何以set開頭的方法都可以 execution(* set*(..))
任何在AccountService 這個接口下面的方法都可以 execution(* com.xyz.service.AccountService.*(..))
任何在com.xyz.service 這個包下面的所有類的所有方法都可以 execution(* com.xyz.service.*.*(..))
任何在com.xyz.service 這個包以及整個包下面的所有子包的所有類的所有方法都可以 execution(* com.xyz.service..*.*(..)) ..代表這個包及這個包下面的所有子包
|
Spring中的5種通知類型及參數
前置通知:在目標方法開始之前進行執行的通知
參數:JoinPoint
後置通知:在目標方法執行之後,無論是否發生異常,都進行執行的通知
參數:JoinPoint
返回通知:在目標方法正常結束時,才執行的通知
參數:JoinPoint,Object
異常通知:在目標方法出現異常時纔會進行執行的通知
參數:JoinPoint,Exception
環繞通知:在目標方法執行之前、 之後都會執行的通知
參數:ProceedingJoinPoint(必須有)
AOP基於註解方式的實現
xml配置中開啓spring註解掃描及開啓aop註解的自動代理
<?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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- 開啓spring的註解驅動 --> <context:component-scan base-package="spring.aop.annotation"></context:component-scan> <!-- 開啓aop的自動代理:使用註解實現AOP,這個必須配置 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
定義接口及接口實現類
此處省略,同xml配置方式相同
通過註解的方式定義切面類
1 /** 2 * 切面 3 */ 4 @Component 5 @Aspect 6 public class UserAspect { 7 //前置通知 8 @Before(value = "execution(* *.add*(..))") 9 public void beforeAdvice(JoinPoint jp){ 10 String name = jp.getSignature().getName(); 11 System.out.println("前置通知的切入點的方法名:" + name); 12 System.out.println("前置通知..."); 13 } 14 15 //後置通知 16 @After(value = "execution(* *.delete*(..))") 17 public void afterAdvice(JoinPoint jp){ 18 String name = jp.getSignature().getName(); 19 System.out.println("後置通知的切入點的方法名:" + name); 20 System.out.println("後置通知..."); 21 } 22 23 //返回通知 24 @AfterReturning(value = "execution(* *.update*(..))",returning="result") 25 public void afterReturningAdvice(JoinPoint jp,Object result){ 26 String name = jp.getSignature().getName(); 27 System.out.println("返回通知的切入點的方法名:" + name); 28 System.out.println(result); 29 System.out.println("返回通知..."); 30 } 31 32 //異常通知 33 @AfterThrowing(value = "execution(* *.getById*(..))",throwing="ex") 34 public void exceptionAdvice(JoinPoint jp,Exception ex){ 35 String name = jp.getSignature().getName(); 36 System.out.println("異常通知的切入點的方法名:" + name); 37 System.out.println(ex.getMessage()); 38 System.out.println("異常通知..."); 39 } 40 41 //環繞通知 42 @Around(value = "execution(* *.batch*(..))") 43 public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ 44 System.out.println("環繞通知前..."); 45 Object result = pjp.proceed(); 46 String name = pjp.getSignature().getName(); 47 System.out.println("環繞通知的切入點的方法名:" + name); 48 System.out.println("環繞通知後..."); 49 return result; 50 } 51 }
測試
1 /** 2 * 註解形式的AOP的單元測試類 3 */ 4 @RunWith(SpringJUnit4ClassRunner.class) 5 @ContextConfiguration("classpath:applicationContext-aop-annotation.xml") 6 public class AnnotationAopTest { 7 @Autowired 8 private UserService userService; 9 10 @Test 11 public void test(){ 12 //註解:前置通知的測試 13 // userService.add(); 14 15 //後置通知的測試 16 // userService.delete(); 17 18 //返回通知 19 // userService.update(); 20 21 //異常通知 22 // userService.getById(); 23 24 //環繞通知 25 userService.batch(); 26 } 27 }