我的编程空间,编程开发者的网络收藏夹
学习永远不晚

spring的pointcut正则表达式的实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

spring的pointcut正则表达式的实现

1.Pointcut表达式各部分的约束规则

在spring中配置切面或者数据库的事务会要求:对具体方法或者是一类特征相同的方法添加日志,事务,或者其他对原方法的增强。这时候就会用到pointcut表达式对方法进行过滤,筛选出符合要求的方法;

既然会涉及到筛选具体的方法,那pointcut一定要匹配出完整的方法路径:全限定类名+方法名;在同一个类中,方法可能被重写而区分重写的方法就是:参数列表;因此pointcut表达式中必须包含这3部分:全限定类名+方法名+参数列表;在spring中还有:访问修饰符,返回值类型;这2个不是必须的;pointcut整体结构:

有了pointcut的整体结构之后就可以根据自己的规则,分别写这几部分的正则表达式了;

  • execution()这部分是固定写法,它包含了完整的表达式;
  • 访问修饰符,返回值,classPath,methodName之间用空格分开;
  • methodName,paramList用()分开;methodName(paramList);

1.1 ACCESS_MODIFIER 访问修饰符

访问修饰符有四种取值:public,private,protected,defalut; " * " ,对访问修饰符不加限制;

1.2 RETURN_TYPE 返回值类型

返回值类型可以是任意类型:8个基础类型 + 对象 + 数组 + void;

  • 基础类型的匹配 BASIC_TYPE: (byte|char|boolean|short|int|long|double|float)
  • 对象匹配:[A-Z]\\w*
  • 返回类型可以是以上2种类型的数组(可以是2维,3维,4维.。。);PARAM_TYPE = (BASIC_TYPE|[A-Z]\\w)(\\[\\])**

最后结合返回值:void, * (表示任意类型);返回值的所有可能取值的正则表达式:(void|PARAM_TYPE|\\*)

1.3 CLASS_PATH 全限定类名

有一个特点:(packageName + “.”) * + className;包名,类名都可以用同一个正则表达式;

CLASS_PATH = "((\\*?\\w+\\*?|\\*)\\.)*(\\*?\\w+\\*?|\\*)";

1.4 EXECUTION 表达式

  METHOD_NAME,PARAM_LIST这2个的匹配分别参照:全限定类名,返回值类型的正则表达式;将这些部分分别写完之后,再按顺序组合一下就可以得到完整的表达式了;再考虑到,写表达式的时候,会习惯性的敲空格,因此可以在合适的地方允许空格;

public class PointcutUtils {
    private static final String ACCESS_MODIFIER = "(public|private|protected|default|\\*)";

    private static final String RETURN_TYPE;

    private static final String CLASS_PATH = "((\\*?\\w+\\*?|\\*)\\.)*(\\*?\\w+\\*?|\\*)";

    private static final String METHOD_NAME = "(\\*?\\w+\\*?|\\*)";

    private static final String PARAM_LIST ;

    private static final String EXECUTION ;
    //基础类型
    private static final String BASIC_TYPE="(byte|char|boolean|short|int|long|double|float)";
    //参数类型
    private static final String PARAM_TYPE;


    static{
        //参数类型:基础类型 + Object + 数组类型
        PARAM_TYPE = "("+BASIC_TYPE+"|[A-Z]\\w*)(\\[\\])*";
        //返回值类型:void  + 参数类型
        RETURN_TYPE="(void|"+PARAM_TYPE+"|\\*)";
        //参数列表
        PARAM_LIST = "(\\.\\.|"+PARAM_TYPE+"(\\s*,\\s*"+PARAM_TYPE+")*" +"|)";
        //execution表达式
        EXECUTION = "\\s*execution\\s*\\(\\s*"+ACCESS_MODIFIER+"\\s+"+RETURN_TYPE+"\\s+"+CLASS_PATH+"\\s+"+METHOD_NAME+"\\(\\s*"+PARAM_LIST+"\\s*\\)\\s*"+"\\s*\\)\\s*";

    }
	//检测pointcut是否是正确的
    static boolean  checkPointcut(String pointcutReg){
        return pointcutReg == null ? false : pointcutReg.matches(EXECUTION);
    }

}

得到的EXECUTION表达式可以用来检测pointcut表达式是否写正确;
测试:

        String pointcut = "execution ( default int[][] * rr( .. ) ) ";
        //default访问修饰符,int[][]二维数组 ;
        // * 不限定类名; rr 方法名; .. 任意类型的参数列表;符合定义的规则,预期结果为 true
        boolean correct = PointcutUtils.checkPointcut(pointcut );
        System.out.println(correct);//结果:true

2.拆分pointcut表达式

拆分流程:

代码:

	//拆分pointcut
    public static Pointcut parsePointcut(String pointcut){
        if(!checkPointcut(pointcut))throw new IllegalArgumentException("execution grammar format error.");
        String exeReg = getBracketStr(pointcut);//获取execution();中括号包裹的部分;
        String paramList = getBracketStr(exeReg).replaceAll(" ","");
        int start = exeReg.indexOf("(");
        exeReg = exeReg.substring(0,start);
        String[] regs = exeReg.split("\\s+");
        String accessModifier = regs[0];
        String returnType = regs[1];
        String classPath = regs[2];
        String methodName = regs[3];
        return new Pointcut(accessModifier,returnType,classPath,methodName,paramList);
    }
    static String getBracketStr(String str){
        int start = str.indexOf("(");
        int end = str.lastIndexOf(")");
        return str.substring(start+1,end).trim();
    }

3.过滤

  分别匹配class和method;在拿到pointcut的时候,如何匹配class和method呢?这个时候要对类路径的正则表达式做一下处理;比如:pointcut的classpath部分:

"*weqq*.dgdfgfg.df*"

*weqq*:我们希望能匹配到包名含有 weqq的包;直接使用这个作为正则表达式去匹配类路径肯定是不行的;

 * ====》 重复匹配0次或多次前一个字符或者表达式;
 
如何能达到要求呢?只需要做一下简单处理就好了:*weqq* ====》 \\w*weqq\\w*;将 * 替换成 \\w* 就可以匹配字符了

还有需要注意的是 ".",在正则表达式中表示匹配任意字符;

而我们希望它只是包的分割符,它只表示" . ",而不需要有任何其他的含义,因此需要将 "."转换成普通字符    :  .  ===>   \\.

匹配class的类名

 public static boolean matchClass(Pointcut pointcut,Class cla){
        if(pointcut.getClassPath().equals("*"))return true;
        return cla.getTypeName().matches(pointcut.getClassPath().replaceAll("\\*","\\\\w*").replaceAll("\\.","\\\\."));
    }


匹配方法:访问修饰符,返回值,方法名,参数列表


   public static boolean matchMethod(Pointcut pointcut, Method method){
       return matchModifier(pointcut.getAccessModifier(),method) &&
              matchReturnType(pointcut.getReturnType(),method) &&
              matchMethodName(pointcut.getMethodName(),method) &&
              matchParamList(pointcut.getParamList(),method);


   }

   static boolean matchModifier(String modifier,Method method){
       int modifiers = method.getModifiers();
        switch (modifier){
            case "default"  :return method.isDefault();
            case "public"   :return Modifier.isPublic(modifiers);
            case "private"  :return Modifier.isPrivate(modifiers);
            case "protected":return Modifier.isProtected(modifiers);
            case "*"        :return true;
            default:
                return false;
        }
   }

   static boolean matchReturnType(String returnType,Method method){
        if(returnType.equals("*"))return true;
       return returnType.equals(method.getReturnType().getSimpleName());
   }

   static boolean matchMethodName(String name,Method method){
        if(name.equals("*"))return true;
        return method.getName().matches(name.replaceAll("\\*","\\\\w*"));
   }

   static boolean matchParamList(String paramList,Method method){

        if(paramList.equals(".."))return true;

       Class<?>[] parameterTypes = method.getParameterTypes();
       if((paramList.equals("")) ){
           if( parameterTypes.length == 0 )return true;
           else return false;
       }
       StringBuilder methodParamList = new StringBuilder();
       for (Class<?> parameterType : parameterTypes) {
           methodParamList.append(","+parameterType.getSimpleName());
       }
        String methodParam =  methodParamList.toString().substring(1);
        return methodParam.equals(paramList);

   }

同时匹配上类和方法,就可以对方法增强了;其实可以看到在实现pointcut表达式只用到了少量的正则表达式的知识;execution整体拼凑起来有点多,但是分开来看每部分还是简单的;只需要了解简单的正则和反射,就可以自定义一个pointcut过滤器了。有了这个之后,就可以自己定义实现选择性AOP了;

到此这篇关于spring的pointcut正则表达式的实现的文章就介绍到这了,更多相关spring pointcut正则表达式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

spring的pointcut正则表达式的实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

spring的pointcut正则表达式的实现

本文主要介绍了spring的pointcut正则表达式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

Python正则表达式怎么实现

这篇文章主要讲解了“Python正则表达式怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python正则表达式怎么实现”吧!1. 正则表达式_匹配单个字符# ### 正则表达式 -
2023-06-21

只能输入正整数的正则表达式及常用的正则表达式

只能输入正整数的正则表达式:^[1-9]\d*$常用的正则表达式:1. 匹配手机号码:^[1][3,4,5,7,8,9]\d{9}$2. 匹配邮箱地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
2023-08-16

Python中的正则表达式

正则表达式 是包含文本和特殊字符的字符串, 为高级的文本模式匹配, 抽取, 与文本形式的搜索和替换功能提供了基础Python通过标准库re模块来支持正则表达式模式匹配的两种方法完成匹配(模式匹配)搜索(search())匹配(match()
2023-01-31

如何实现检查email的正则表达式

这篇文章将为大家详细讲解有关如何实现检查email的正则表达式,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。怎么验证一个email地址. 在一个完整的email地址中有三个部分: POP3 用户名 (在
2023-06-17

java正则表达式的实例用法

本篇内容介绍了“java正则表达式的实例用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java正则表达式实例详解 创建正则表达式你可以从
2023-06-03

Linux的正则表达式实例分析

今天小编给大家分享一下Linux的正则表达式实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。正则表达式(regular
2023-06-27

基于Java的正则表达式

正则表达式概念 正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。
2023-05-31

浅谈Python的正则表达式

这篇文章主要介绍了浅谈Python的正则表达式,正则表达式本身是独立于编程语言的知识,但是它又依附于编程语言,需要的朋友可以参考下
2023-05-17

python正则表达式如何实现分组

这篇文章将为大家详细讲解有关python正则表达式如何实现分组,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。分组格式:(\w)注:在正则表达式中一对括号包围的内容表示分组,正则表达式中可以有多个分组用处:
2023-06-26

JAVA正则表达式过滤文件的实现方法

JAVA正则表达式过滤文件的实现方法 正则表达式过滤文件列表,听起来简单,如果用java实现,还真需要一番周折,本文简析2种方式 1、适用于路径确定,文件名时正则表达式的情况(jdk6的写法)String filePattern = "/
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录