AOP的實現

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 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章