Java進階知識23 Spring execution 切入點表達式


1、概述        

  切入點(execution ):可以對指定的方法進行攔截,從而給指定的類生成代理對象。(攔截誰,就是在誰那里切入指定的程序/方法)

  格式:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

參數解析:

  modifiers-pattern?:指定方法的修飾符,支持通配符,該部分可以省略。(public/private/protected
  ret-type-pattern:指定方法的返回值類型,支持通配符,可以使用 * 來匹配所有的返回值類型。
  declaring-type-pattern?:指定方法所屬的,支持通配符,該部分可以省略。(要切入的類:class
  name-pattern:指定要匹配的方法名,支持通配符,可以使用"*"通配符來匹配所有方法。(要切入的方法
  param-pattern:指定方法聲明中的形參列表,支持兩個通配符,即"*"和"..",其中“*”代表一個任意類型的參數,而“..”代表零個或多個任意類型的參數。例如,() 匹配一個不接受任何參數的方法,而(..) 匹配一個接受任意數量參數的方法,(*)匹配了一個接受一個任何類型的參數的方法,(*,String)匹配了一個接受兩個參數的方法,其中第一個參數是任意類型,第二個參數必須是String類型。(要切入的方法的參數列表
  throws-pattern:指定方法聲明拋出的異常,支持通配符,該部分可以省略

切入點語法常用的幾種:

 1 <!-- 切入點表達式語法: -->
 2 <!-- 【1、攔截所有public方法】 -->
 3 <aop:pointcut expression="execution(public * *(..))" id="pt"/> 
4
5 <!-- 【2、攔截所有save開頭的方法】 --> 6 <aop:pointcut expression="execution(* save*(..))" id="pt"/>
7
8 <!-- 【3、攔截指定類的指定方法, 攔截時候一定要定位到方法】 --> 9 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/> 10 11 <!-- 【4、攔截指定類的所有方法】 --> 12 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.*(..))" id="pt"/>
13 14 <!-- 【5、攔截指定包,以及其自包下所有類的所有方法】 --> 15 <aop:pointcut expression="execution(* com..*.*(..))" id="pt"/>
16 17 <!-- 【6、多條件】 --> 18 <!-- 或:|| or --> 19 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) || execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />
20 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) or execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />
21 22 <!-- 且:&amp;&amp; and --> <!-- 語法雖然沒錯,但,沒意義 --> 23 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) &amp;&amp; execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" /> 24 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) and execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />
25 26 <!-- 【7、取非值:not ! 不攔截指定的規則,攔截除此之外的所有類的方法】 --> 27 <aop:pointcut expression="!execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/>
28 <!-- 注意not前必須有空格 --> 29 <aop:pointcut expression=" not execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/>

2、實例        

用到的jar包:

    

相關代碼:

 1 //接口
 2 public interface IUserDao {
 3     public void save();
 4 }
 5 
 6 //接口實現類
 7 public class UserDao implements IUserDao {
 8 
 9     @Override
10     public void save() { //3、執行業務方法
11         System.out.println("3、保存用戶成功!");
12     }
13 }

MessageDao 類(此類,沒有實現任何接口)

1 public class MessageDao {
2     public void save() { //3、執行業務方法
3         System.out.println("3、保存信息成功!");
4     }
5 }

Aop 類

 1 package com.shore.aop;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 /**
 6  * @author DSHORE/2019-11-7
 7  *
 8  */
 9 public class Aop {
10     //around:環繞; ProceedingJoinPoint:必須添加(執行)
11     @SuppressWarnings("unused")
12     private void around(ProceedingJoinPoint pjp) throws Throwable {
13         System.out.println("2、環繞前....");
14         pjp.proceed();  // 執行目標方法(業務代碼)
15         System.out.println("5、環繞后....");
16     }
17     
18     public void begin() {
19         System.out.println("1、開啟事務......");
20     }
21     
22     public void commit() {
23         System.out.println("6、提交事務......");
24     }
25     
26     public void afterReturning() {
27         System.out.println("4、afterReturning(),返回消息");
28     }
29     
30     //有異常,執行這個第四步;沒有異常,則執行上面的第四步
31     public void afterThrowing(){
32         System.out.println("4、afterThrowing(),返回異常消息");
33     }
34 }

Spring 配置文件(beans.xml)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 4     xmlns:tx="http://www.springframework.org/schema/tx"
 5     xsi:schemaLocation="
 6        http://www.springframework.org/schema/beans
 7        http://www.springframework.org/schema/beans/spring-beans.xsd
 8        http://www.springframework.org/schema/tx
 9        http://www.springframework.org/schema/tx/spring-tx.xsd
10        http://www.springframework.org/schema/aop
11        http://www.springframework.org/schema/aop/spring-aop.xsd">
12 
13     <!-- dao類 -->
14     <bean id="userDao" class="com.shore.dao.impl.UserDao"></bean>
15     <bean id="messageDao" class="com.shore.dao.impl.MessageDao"></bean>
16 
17     <!-- 注入切面類 -->
18     <bean id="aop" class="com.shore.aop.Aop"></bean>
19 
20     <aop:config>
21         <!-- 配置切入點 -->
22         <!-- 切入點表達式語法: -->
23         <!-- 【1、攔截所有public方法】 -->  <!-- 【第一個*是返回類型,第二個*是方法名 -->
24         <!-- <aop:pointcut expression="execution(public * *(..))" id="pt" /> -->
25         
26         <!-- 【2、攔截所有save開頭的方法】 -->
27         <!-- <aop:pointcut expression="execution(* save(..))" id="pt" /> -->
28         
29         <!-- 【3、攔截指定類的指定方法, 攔截時候一定要定位到方法】 -->
30         <!-- <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..))" id="pt" /> -->
31         
32         <!-- 【4、攔截指定類的所有方法】 -->
33         <!-- <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" /> -->
34         
35         <!-- 【5、攔截指定包,以及其自包下所有類的所有方法】 -->
36         <!-- <aop:pointcut expression="execution(* com..*.*(..))" id="pt" /> -->
37         <!-- <aop:pointcut expression="execution(* com..UserDao.*(..))" id="pt" /> -->
38         
39         <!-- 6、多條件 -->
40         <!-- 【(1)或:or   ||】 -->
41         <!-- <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) or execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" /> -->
42         <!-- 【(2)與:and   &amp;&amp;】 -->
43         <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) and execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />
44         
45         <!-- 【7、否定:!  not(not前后都需要空格)】 -->
46         <!-- <aop:pointcut expression="!execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" /> -->
47         <aop:pointcut expression=" not execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" />
48         
49         
50         <!-- 配置切面(切入點形成的類,切入點就是重復的代碼/方法) -->
51         <aop:aspect ref="aop">
52             <!-- 1、開啟事務。。。。。。 -->
53             <aop:before method="begin" pointcut-ref="pt" />
54             <!-- 6、提交事務 -->
55             <aop:after method="commit" pointcut-ref="pt" />
56             <!-- 環繞2/5 -->
57             <aop:around method="around" pointcut-ref="pt" />
58             <!-- 4、afterReturning -->
59             <aop:after-returning method="afterReturning"
60                 pointcut-ref="pt" />
61             <!-- 4、異常(程序出現異常,執行這個第四步;沒有異常,則執行上面的第四步) -->
62             <aop:after-throwing method="afterThrowing"
63                 pointcut-ref="pt" />
64         </aop:aspect>
65     </aop:config>
66 </beans>

測試類

 1 package com.shore.test;
 2 
 3 import org.junit.Test;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.support.ClassPathXmlApplicationContext;
 6 
 7 import com.shore.dao.IUserDao;
 8 import com.shore.dao.impl.MessageDao;
 9 
10 /**
11  * @author DSHORE/2019-11-7
12  *
13  */
14 public class MyTest {
15     @Test
16     public void testUserDao() {
17         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
18         IUserDao userDao = (IUserDao) context.getBean("userDao");
19         //$Proxy4 :class com.sun.proxy.$Proxy4
20         System.out.println("這個相當於動態代理$Proxy4:"+userDao);//返回值:com.shore.dao.impl.UserDao@73aecc3a
21         userDao.save();
22         System.out.println("=============== 分割線 ===============");
23         
24         MessageDao messageDao = (MessageDao) context.getBean("messageDao");
25         System.out.println("這個相當於Cglib子類代理:"+messageDao);//返回值:com.shore.dao.impl.MessageDao@15412e75
26         messageDao.save();
27     }
28 }

 

 

上方實例,切入點出代碼,詳細解析:

  1、攔截所有public方法

1 <!-- 【1、攔截所有public方法】 -->  <!-- 第一個*是返回值類型,第二個*是方法名;兩個..表示可以是兩個或者是多個參數 -->
2 <aop:pointcut expression="execution(public * *(..))" id="pt" />  

運行結果圖:

解析:

  從上面的項目截圖以及相關代碼,可以看出:只有三個public 方法,Aop類中的不算,因為他是切面類。故,上面紅框中的結果,大家不難理解。沒有紅框的兩處代碼,是對IUserDao類進行攔截,輸出兩遍,是因為測試類,調用它兩遍。

2、攔截所有save開頭的方法

1 <!-- 【2、攔截所有save開頭的方法】 -->  <!-- 第一個*是返回類型,兩個..表示可以是兩個或者是多個參數 -->
2 <aop:pointcut expression="execution(* save(..))" id="pt" />  

運行結果圖:

解析省略(看結果圖中的紅色文字)

3、攔截指定類的指定方法, 攔截時候一定要 定位到方法

1 <!-- 【3、攔截指定類的指定方法, 攔截時候一定要定位到方法】 -->   <!-- 第一個*是返回類型,兩個..表示可以是兩個或者是多個參數 -->
2 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..))" id="pt" />

運行結果圖:

解析:

  從上面的代碼和結果圖,可以看出,這里只對UserDao類中的save方法進行攔截。雖然MessageDao類中的save方法也運行了,但是,沒有開啟事務,也沒提交事務,故不會生效。

4、攔截指定類的所有方法

1 <!-- 【4、攔截指定類的所有方法】 -->  <!-- 第一個*是返回值類型,第二個*是方法名;兩個..表示可以是兩個或者是多個參數 -->
2 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" />

運行結果圖:

 解析省略(和上面第3點一樣,UserDao類中,有多少個方法,就執行多少個,結果類似)

5、攔截指定包,以及其自包下所有類的所有方法

1 <!-- 【5、攔截指定包,以及其自包下所有類的所有方法】 -->
2 <aop:pointcut expression="execution(* com..*.*(..))" id="pt" /><!-- 這幾個*分別是 返回類型、com包下的所有類、指定類下的所有方法 -->
3 <aop:pointcut expression="execution(* com..UserDao.*(..))" id="pt" />

運行結果圖:

 

解析省略(和上面的測試結果類似)

6、多條件

1 <!-- 6、多條件 -->
2 <!-- 【(1)或:or   ||】 -->
3 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) or execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />
4 <!-- 【(2)與:and   &amp;&amp;】 -->
5 <aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) and execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />

運行結果圖:

 

解析省略(看結果圖中的紅色文字)

7、否定: !  not(注意:not前后都需要空格)

1 <!-- 【7、否定: !  not(not前后都需要空格)】 -->
2 <aop:pointcut expression="!execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" />
3 <aop:pointcut expression=" not execution(* com.shore.dao.impl.UserDao.*(..))" id="pt" />

運行結果圖:

解析省略(看結果圖中的紅色文字)

本文總結: 經測試結果顯示,做修飾符public/private/protected)和否定(!  not)測試時,連接口類都一起攔截。除這兩種以外,只要是指定了包名、類名、方法名的 等等,都不會再去攔截接口類。

 

 

 

 

 

 

原創作者:DSHORE

作者主頁:http://www.cnblogs.com/dshore123/

原文出自:https://www.cnblogs.com/dshore123/p/11823849.html

歡迎轉載,轉載務必說明出處。(如果本文對您有幫助,可以點擊一下右下角的 推薦,或評論,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM