• 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

    欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!

  • 相关阅读:
    python 线程 进程 标识
    创建2600个文件 批量创建文件 文件夹
    Do not use the <section> element as a generic container; this is what <div> is for, especially when the sectioning is only for styling purposes.
    js json
    大量陈旧进程的批量杀死
    positive 相对其正常位置,那什么是正常位置: 请问调试,请问浏览器
    CSS3 弹性盒子(Flex Box) 微信小程序图片通栏
    SHOW PROCESSLIST Syntax
    How MySQL Opens and Closes Tables refuse connections 拒绝连接的原因 file descriptors
    1250太小了 mysql 并发
  • 原文地址:https://www.cnblogs.com/dshore123/p/11823849.html
Copyright © 2020-2023  润新知