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正则表达式内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

spring的pointcut正则表达式的实现的更多相关文章

  1. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. ios – 使用大写符号在字符串swift中获取URL的正则表达式

    我尝试在文本中获取URL.所以,在此之前,我使用了这样一个表达式:但是当用户输入带有大写符号的URL时(例如Http://Google.com,它与它不匹配)我遇到了问题.我试过了:但什么都没发生.解决方法您可以使用正则表达式中的i内联标志关闭区分大小写,有关可用正则表达式功能的详细信息,请参阅FoundationFrameworkReference.(?ismwx-ismwx)Flagsetti

  3. ios – 如何在Swift 3中使用正则表达式?

    解决方法我相信.当没有其他选项适用时,将使用.allZeros.因此,使用Swift3,您可以传递一个空的选项列表或省略options参数,因为它默认为无选项:要么请注意,在Swift3中,您不再使用error参数.它现在抛出.

  4. ios – lldb断点在类目标c中的所有方法

    如何使用lldb在ObjectiveC类中的所有方法上自动设置断点?

  5. swift的正则表达式(NSRegularExpression)

    init(_pattern:String){varerror:NSError?

  6. swift 正则表达式运用实例选自《swifter 100个swift开发必备tip 》

  7. Swift截取HTML中的所有图片url

    在Swift中,要从HTML格式的String中截取出所有的img的所有图片url,要截取的url就要匹配url,需要用到正则表达式。

  8. 收藏swift正则表达式的各种验证

    1.验证邮箱classfuncvalidateEmail(email:String)->Bool{varemailString="[A-Z0-9a-z._%-]@[A-Za-z0-9.-]\\.[A-Za-z]{2,4}"varemailPredicate=nspredicate(format:"SELFMATCHES%@",emailString)returnemailPredicate.eva

  9. Swift3.0-正则表达式 &lt;待续&gt;

    贡献者:赵大财博客:https://my.oschina.net/zhaodacaiGitHub:https://github.com/zhaodacai邮箱:zhaodacai@yeah.comQQ:327532817=============================先直接来代码:NSRegularExpression.OptionscaseInsensitive不区分大小写allowC

  10. 迅速 – IBInspectable创建一个下拉和更好的组织

    简而言之,我想创建一个@IBInspectable属性,使您可以在故事板中从下拉菜单中选择一系列的内容.另外如果有办法创建分隔符,更好地组织IBInspectables,我想知道这是否也可能.在我的示例中,我想为电话号码创建正则表达式字符串,以便当我去故事板时,我可以在下拉菜单中选择“电话号码”项,而不是输入正则表达式字符串.目前,我已经将一个TextField子类化,以便我可以将更多的IBIns

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部