【spy++ 源码】【macscript源码】【jdkc源码】find_in_set源码

时间:2024-12-29 09:44:56 编辑:zbar源码编译 来源:源码最大整数

1.mybatis插件机制源码解析
2.MySQL 简单查询语句执行过程分析(四)WHERE 条件
3.python常用代码?

find_in_set源码

mybatis插件机制源码解析

       引言

       本篇源码解析基于MyBatis3.5.8版本。

       首先需要说明的是,本篇文章不是mybatis插件开发的教程,而是从源码层面分析mybatis是如何支持用户自定义插件开发的。

       mybatis的插件机制,让其扩展能力大大增加。spy++ 源码比如我们项目中经常用到的PageHelper,这就是一款基于mybatis插件能力开发的产品,它的功能是让基于mybatis的数据库分页查询更容易使用。

       当然基于插件我们还可以开发其它功能,比如在执行sql前打印日志、做权限控制等。

正文

       mybatis插件也叫mybatis拦截器,它支持从方法级别对mybatis进行拦截。macscript源码整体架构图如下:

       解释下几个相关概念:

       Interceptor拦截器接口,用户自定义的拦截器就是实现该接口。

       InterceptorChain拦截器链,其内部维护一个interceptorslist,表示拦截器链中所有的拦截器,并提供增加或获取拦截器链的方法。比如有个核心的方法是pluginAll。该方法用来生成代理对象。

       Invocation拦截器执行时的上下文环境,其实就是目标方法的调用信息,包含目标对象、调用的方法信息、参数信息。核心方法是jdkc源码proceed。该方法的主要目的就是进行处理链的传播,执行完拦截器的方法后,最终需要调用目标方法的invoke方法。

       mybatis支持在哪些地方进行拦截呢?你只需要在代码里搜索interceptorChain.pluginAll的使用位置就可以获取答案,一共有四处:

parameterHandler=(ParameterHandler)interceptorChain.pluginAll(parameterHandler);resultSetHandler=(ResultSetHandler)interceptorChain.pluginAll(resultSetHandler);statementHandler=(StatementHandler)interceptorChain.pluginAll(statementHandler);executor=(Executor)interceptorChain.pluginAll(executor);

       这四处实现的原理都是一样的,我们只需要选择一个进行分析就可以了。

       我们先来看下自定义的插件是如何加载进来的,比如我们使用PageHelper插件,通常会在mybatis-config.xml中加入如下的配置:

<plugins><plugininterceptor="com.github.pagehelper.PageInterceptor"><!--configparamsasthefollowing--><propertyname="param1"value="value1"/></plugin></plugins>

       mybatis在创建SqlSessionFactory的时候会加载配置文件,

publicConfigurationparse(){ if(parsed){ thrownewBuilderException("EachXMLConfigBuildercanonlybeusedonce.");}parsed=true;parseConfiguration(parser.evalNode("/configuration"));returnconfiguration;}

       parseConfiguration方法会加载包括plugins在内的很多配置,

privatevoidparseConfiguration(XNoderoot){ try{ ...pluginElement(root.evalNode("plugins"));...}catch(Exceptione){ thrownewBuilderException("ErrorparsingSQLMapperConfiguration.Cause:"+e,e);}}privatevoidpluginElement(XNodeparent)throwsException{ if(parent!=null){ for(XNodechild:parent.getChildren()){ Stringinterceptor=child.getStringAttribute("interceptor");Propertiesproperties=child.getChildrenAsProperties();InterceptorinterceptorInstance=(Interceptor)resolveClass(interceptor).getDeclaredConstructor().newInstance();interceptorInstance.setProperties(properties);configuration.addInterceptor(interceptorInstance);}}}

       pluginElement干了几件事情:

       创建Interceptor实例

       设置实例的属性变量

       添加到Configuration的interceptorChain拦截器链中

       mybatis的插件是通过动态代理实现的,那肯定要生成代理对象,生成的lsmod源码逻辑就是前面提到的pluginAll方法,比如对于Executor生成代理对象就是,

executor=(Executor)interceptorChain.pluginAll(executor);

       接着看pluginAll方法,

/***该方法会遍历用户定义的插件实现类(Interceptor),并调用Interceptor的plugin方法,对target进行插件化处理,*即我们在实现自定义的Interceptor方法时,在plugin中需要根据自己的逻辑,对目标对象进行包装(代理),创建代理对象,*那我们就可以在该方法中使用Plugin#wrap来创建代理类。*/publicObjectpluginAll(Objecttarget){ for(Interceptorinterceptor:interceptors){ target=interceptor.plugin(target);}returntarget;}

       这里遍历所有我们定义的拦截器,调用拦截器的plugin方法生成代理对象。有人可能有疑问:如果有多个拦截器,autolot源码target不是被覆盖了吗?

       其实不会,所以如果有多个拦截器的话,生成的代理对象会被另一个代理对象代理,从而形成一个代理链条,执行的时候,依次执行所有拦截器的拦截逻辑代码。

       plugin方法是接口Interceptor的默认实现类,

defaultObjectplugin(Objecttarget){ returnPlugin.wrap(target,this);}

       然后进入org.apache.ibatis.plugin.Plugin#wrap,

publicstaticObjectwrap(Objecttarget,Interceptorinterceptor){ Map<Class<?>,Set<Method>>signatureMap=getSignatureMap(interceptor);Class<?>type=target.getClass();Class<?>[]interfaces=getAllInterfaces(type,signatureMap);if(interfaces.length>0){ returnProxy.newProxyInstance(type.getClassLoader(),interfaces,newPlugin(target,interceptor,signatureMap));}returntarget;}

       首先是获取我们自己实现的Interceptor的方法签名映射表。然后获取需要代理的对象的Class上声明的所有接口。比如如果我们wrap的是Executor,就是Executor的所有接口。然后就是最关键的一步,用Proxy类创建一个代理对象(newProxyInstance)。

       注意,newProxyInstance方法的第三个参数,接收的是一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

       我们这里传入的是Plugin类,故在动态运行过程中会执行Plugin的invoker方法。

       如果对这一段不是很理解,建议先了解下java动态代理的原理。java动态代理机制中有两个重要的角色:InvocationHandler(接口)和Proxy(类),这个是背景知识需要掌握的。

       我们在深入看下上面的getSignatureMap方法,

privatestaticMap<Class<?>,Set<Method>>getSignatureMap(Interceptorinterceptor){ //从Interceptor的类上获取Intercepts注解,说明我们自定义拦截器需要带注解InterceptsinterceptsAnnotation=interceptor.getClass().getAnnotation(Intercepts.class);//issue#if(interceptsAnnotation==null){ thrownewPluginException("No@Interceptsannotationwasfoundininterceptor"+interceptor.getClass().getName());}Signature[]sigs=interceptsAnnotation.value();Map<Class<?>,Set<Method>>signatureMap=newHashMap<>();//解析Interceptor的values属性(Signature[])数组,存入HashMap,Set<Method>>for(Signaturesig:sigs){ Set<Method>methods=MapUtil.computeIfAbsent(signatureMap,sig.type(),k->newHashSet<>());try{ Methodmethod=sig.type().getMethod(sig.method(),sig.args());methods.add(method);}catch(NoSuchMethodExceptione){ thrownewPluginException("Couldnotfindmethodon"+sig.type()+"named"+sig.method()+".Cause:"+e,e);}}returnsignatureMap;}

       首先需要从Interceptor的类上获取Intercepts注解,说明我们自定义拦截器需要带注解,比如PageHelper插件的定义如下:

<plugins><plugininterceptor="com.github.pagehelper.PageInterceptor"><!--configparamsasthefollowing--><propertyname="param1"value="value1"/></plugin></plugins>0

       所以我们可以知道,getSignatureMap其实就是拿到我们自定义拦截器声明需要拦截的类以及类对应的方法。

       前面说过,当我们调用代理对象时,最终会执行Plugin类的invoker方法,我们看下Plugin的invoker方法,

<plugins><plugininterceptor="com.github.pagehelper.PageInterceptor"><!--configparamsasthefollowing--><propertyname="param1"value="value1"/></plugin></plugins>1

       Interceptor接口的intercept方法就是我们自定义拦截器需要实现的逻辑,其参数为Invocation,可从Invocation参数中拿到执行方法的对象,方法,方法参数,比如我们可以从statementHandler拿到SQL语句,实现自己的特殊逻辑。

       在该方法的结束需要调用invocation#proceed()方法,进行拦截器链的传播。

       参考:

       blogs.com/chenpi/p/.html

MySQL 简单查询语句执行过程分析(四)WHERE 条件

       MySQL WHERE 条件查询执行过程深入解析

       MySQL简单查询语句执行系列的第 4 篇深入探讨 WHERE 条件在查询中的作用。我们分为三个部分讲解:

       WHERE条件的源码结构:MySQL对多层嵌套的WHERE条件进行树状简化,减少处理层级以提高执行效率。

       条件判断过程:以示例SQL为例,依次检查Item_cond_or和Item_cond_and的真假,通过逐层比较确定记录是否匹配。

       特殊类型字段比较:set、enum和bit字段的特殊比较规则,如find_in_set函数、整数转换和位操作。

       1. WHERE条件结构示例:SQL中的where条件形成树状结构,如i1 > and e1 = '成都',会在语法分析阶段合并简化。

       比较过程示例:读取记录后,逐层检查Item_cond_or,如'e1 = '成都'使用字符串比较函数func进行判断。

       3. 特殊字段比较:

       set字段:以整数形式存储,通过遍历选项判断字符串值是否匹配。

       enum字段:整数值直接比较,无需转换。

       bit字段:支持整数和二进制比较,包括位操作。

       了解更多细节,请继续关注我们接下来的MySQL简单查询语句执行分析系列(五)- 发送数据。

python常用代码?

       Python中的常用内置函数有哪些呢?

       ï¼ˆ1)Lambda函数

       ç”¨äºŽåˆ›å»ºåŒ¿åå‡½æ•°ï¼Œå³æ²¡æœ‰åç§°çš„函数。它只是一个表达式,函数体比def简单很多。当我们需要创建一个函数来执行单个操作并且可以在一行中编写时,就可以用到匿名函数了。

       Lamdba的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

       åˆ©ç”¨Lamdba函数,往往可以将代码简化许多。

       ï¼ˆ2)Map函数

       ä¼šå°†ä¸€ä¸ªå‡½æ•°æ˜ å°„到一个输入列表的所有元素上,比如我们先创建了一个函数来返回一个大写的输入单词,然后将此函数应有到列表colors中的所有元素。

       æˆ‘们还可以使用匿名函数lamdba来配合map函数,这样可以更加精简。

       ï¼ˆ3)Reduce函数

       å½“需要对一个列表进行一些计算并返回结果时,reduce()是个非常有用的函数。举个例子,当需要计算一个整数列表所有元素的乘积时,即可使用reduce函数实现。

       å®ƒä¸Žå‡½æ•°çš„最大的区别就是,reduce()里的映射函数(function)接收两个参数,而map接收一个参数。

       ï¼ˆ4)enumerate函数

       ç”¨äºŽå°†ä¸€ä¸ªå¯éåŽ†çš„数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在for循环当中。

       å®ƒçš„两个参数,一个是序列、迭代器或其他支持迭代对象;另一个是下标起始位置,默认情况从0开始,也可以自定义计数器的起始编号。

       ï¼ˆ5)Zip函数

       ç”¨äºŽå°†å¯è¿­ä»£çš„对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表

       å½“我们使用zip()函数时,如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。

       python必背入门代码是什么

       python必背入门代码列举如下:

       1、大写第一个字母。以下代码块会使用title()方法,从而大写字符串中每一个单词的首字母。

       s="programmingisawesome"

       print(s.title())

       #ProgrammingIsAwesome

       2、字符元素组成判定。检查两个字符串的组成元素是不是一样的。

       fromcollectionsimportCounter

       defanagram(first,second):

       returnCounter(first)==Counter(second)

       anagram("abcd3","3acdb")#True

       3、打印N次字符串。该代码块不需要循环语句就能打印N次字符串。

       n=2

       s="Programming"

       print(s*n)

       #ProgrammingProgramming

       æƒ³äº†è§£æ›´å¤šæœ‰å…³python的详情,推荐咨询达内教育。达内教育致力于面向IT互联网行业,培养软件开发工程师、测试工程师、UI设计师、网络营销工程师、会计等职场人才,目前已在北上海广深等个大中城市成立了家学习中心;更是与多家企业签订人才培养协议,全面助力学员更好就业。感兴趣的话点击此处,免费学习一下

Python常用的正则表达式处理函数详解

       æ­£åˆ™è¡¨è¾¾å¼æ˜¯ä¸€ä¸ªç‰¹æ®Šçš„字符序列,用于简洁表达一组字符串特征,检查一个字符串是否与某种模式匹配,使用起来十分方便。

       åœ¨Python中,我们通过调用re库来使用re模块:

       importre

       ä¸‹é¢ä»‹ç»Python常用的正则表达式处理函数。

       re.match函数

       re.match函数从字符串的起始位置匹配正则表达式,返回match对象,如果不是起始位置匹配成功的话,match()就返回None。

       re.match(pattern,string,flags=0)

       pattern:匹配的正则表达式。

       string:待匹配的字符串。

       flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。具体参数为:

       re.I:忽略大小写。

       re.L:表示特殊字符集\w,\W,\b,\B,\s,\S依赖于当前环境。

       re.M:多行模式。

       re.S:即.,并且包括换行符在内的任意字符(.不包括换行符)。

       re.U:表示特殊字符集\w,\W,\b,\B,\d,\D,\s,\S依赖于Unicode字符属性数据库。

       re.X:为了增加可读性,忽略空格和#后面的注释。

       import?re#从起始位置匹配r1=re.match('abc','abcdefghi')print(r1)#不从起始位置匹配r2=re.match('def','abcdefghi')print(r2)

       è¿è¡Œç»“果:

       å…¶ä¸­ï¼Œspan表示匹配成功的整个子串的索引。

       ä½¿ç”¨group(num)或groups()匹配对象函数来获取匹配表达式。

       group(num):匹配的整个表达式的字符串,group()可以一次输入多个组号,这时它将返回一个包含那些组所对应值的元组。

       groups():返回一个包含所有小组字符串的元组,从1到所含的小组号。

       import?res='This?is?a?demo'r1=re.match(r'(.*)?is?(.*)',s)r2=re.match(r'(.*)?is?(.*?)',s)print(r1.group())print(r1.group(1))print(r1.group(2))print(r1.groups())print()print(r2.group())print(r2.group(1))print(r2.group(2))print(r2.groups())

       è¿è¡Œç»“果:

       ä¸Šè¿°ä»£ç ä¸­çš„(.*)和(.*?)表示正则表达式的贪婪匹配与非贪婪匹配。

       re.search函数

       re.search函数扫描整个字符串并返回第一个成功的匹配,如果匹配成功则返回match对象,否则返回None。

       re.search(pattern,string,flags=0)

       pattern:匹配的正则表达式。

       string:待匹配的字符串。

       flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

       import?re#从起始位置匹配r1=re.search('abc','abcdefghi')print(r1)#不从起始位置匹配r2=re.search('def','abcdefghi')print(r2)

       è¿è¡Œç»“果:

       ä½¿ç”¨group(num)或groups()匹配对象函数来获取匹配表达式。

       group(num=0):匹配的整个表达式的字符串,group()可以一次输入多个组号,这时它将返回一个包含那些组所对应值的元组。

       groups():返回一个包含所有小组字符串的元组,从1到所含的小组号。

       import?res='This?is?a?demo'r1=re.search(r'(.*)?is?(.*)',s)r2=re.search(r'(.*)?is?(.*?)',s)print(r1.group())print(r1.group(1))print(r1.group(2))print(r1.groups())print()print(r2.group())print(r2.group(1))print(r2.group(2))print(r2.groups())

       è¿è¡Œç»“果:

       ä»Žä¸Šé¢ä¸éš¾å‘现re.match与re.search的区别:re.match只匹配字符串的起始位置,只要起始位置不符合正则表达式就匹配失败,而re.search是匹配整个字符串,直到找到一个匹配为止。

       re.compile函数

       compile函数用于编译正则表达式,生成一个正则表达式对象,供match()和search()这两个函数使用。

       re.compile(pattern[,flags])

       pattern:一个字符串形式的正则表达式。

       flags:可选,表示匹配模式,比如忽略大小写,多行模式等。

       import?re#匹配数字r=re.compile(r'\d+')?r1=r.match('This?is?a?demo')r2=r.match('This?is??and?That?is?',0,)r3=r.match('This?is??and?That?is?',8,)?print(r1)print(r2)print(r3)

       è¿è¡Œç»“果:

       findall函数

       æœç´¢å­—符串,以列表形式返回正则表达式匹配的所有子串,如果没有找到匹配的,则返回空列表。

       éœ€è¦æ³¨æ„çš„是,match和search是匹配一次,而findall匹配所有。

       findall(string[,pos[,endpos]])

       string:待匹配的字符串。

       pos:可选参数,指定字符串的起始位置,默认为0。

       endpos:可选参数,指定字符串的结束位置,默认为字符串的长度。

       import?re#匹配数字r=re.compile(r'\d+')?r1=r.findall('This?is?a?demo')r2=r.findall('This?is??and?That?is?',0,)r3=r.findall('This?is??and?That?is?',0,)?print(r1)print(r2)print(r3)

       è¿è¡Œç»“果:

       re.finditer函数

       å’Œfindall类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

       re.finditer(pattern,string,flags=0)

       pattern:匹配的正则表达式。

       string:待匹配的字符串。

       flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等。

       import?re?r=re.finditer(r'\d+','This?is??and?That?is?')for?i?in?r:?print?(i.group())

       è¿è¡Œç»“果:

       re.split函数

       å°†ä¸€ä¸ªå­—符串按照正则表达式匹配的子串进行分割后,以列表形式返回。

       re.split(pattern,string[,maxsplit=0,flags=0])

       pattern:匹配的正则表达式。

       string:待匹配的字符串。

       maxsplit:分割次数,maxsplit=1分割一次,默认为0,不限次数。

       flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等。

       import?re?r1=re.split('\W+','This?is??and?That?is?')?r2=re.split('\W+','This?is??and?That?is?',maxsplit=1)?r3=re.split('\d+','This?is??and?That?is?')?r4=re.split('\d+','This?is??and?That?is?',maxsplit=1)?print(r1)print(r2)print(r3)print(r4)

       è¿è¡Œç»“果:

       re.sub函数

       re.sub函数用于替换字符串中的匹配项。

       re.sub(pattern,repl,string,count=0,flags=0)

       pattern:正则中的模式字符串。

       repl:替换的字符串,也可为一个函数。

       string:要被查找替换的原始字符串。

       count:模式匹配后替换的最大次数,默认0表示替换所有的匹配。

       import?re?r='This?is??and?That?is?'#?删除字符串中的数字r1=re.sub(r'\d+','',r)print(r1)#?删除非数字的字符串?r2=re.sub(r'\D','',r)print(r2)

       è¿è¡Œç»“果:

       åˆ°æ­¤è¿™ç¯‡å…³äºŽPython常用的正则表达式处理函数详解的文章就介绍到这了,希望大家以后多多支持!

python必背入门代码是什么?

       python必背入门代码是Reversingastringusingslicingmy_string"ABCDE"reversed_string=my_string[::-1]print(reversed_string)。

       å½“你定义一个a=3的时候,系统在内存中会给a一个地址,而这个a就是代表一个门牌号,然后小3住在里面,当你要调用a的时候,就相当于你喊了一句:小3,出来玩儿了!当你改好了这个房子之后,门牌号a是不能改变的,但住在里面的小3是可以换人的,所以称之为变量,而不是恒量。

       python经历

       åœ¨çŸ¥ä¹Žå’ŒCSDN的圈子里,经常看到、听到一些python初学者说,学完基础语法后,不知道该学什么,学了也不知道怎么用,一脸的茫然。

       è¿‘日,CSDN的公众号推送了一篇博客,题目叫做《迷思:Python学到什么程度可以面试工作?》,真实反映了python程序员在成长过程中的一些困惑。从年开始接触python这门编程语言,从年开始单一使用python应对所有的开发工作,直至今天。

       å›žé¡¾è‡ªå·±çš„学习过程,也曾经遇到过无数的困难,也曾经迷茫过、困惑过。本文所列举的这个模块,是我在工作和学习中用过的或者正在学习的,算是对自己过去年的学习总结。希望对处在迷茫中的程序员有所帮助。

python必背入门代码是什么?

       å…·ä½“如下:

       1、反转字符串:

       #Reversingastringusingslicing

       my_string="ABCDE”

       reversedstring=my_string[::-1]

       print(reversed_string)

       #output

       #EDCBA

       2、使用标题类:

       my_string="mynameischaitanyabaweja"

       newstring=mystring.title(

       print(new_string)

       #MyNameIschaitanyaBaweja

       3、查找字符串的唯一要素:

       my_string="aavvccccddddeee"

       temp_set=set(my_string)

       newstring=-join(temp_set)

       print(new_string)

       4、输出n次字符串或列表:

       n=3

       my_string="abcd"my_list=[1,2,3]

       print(my_string*n)

       print(my_list*n)

       importstreamlitasst

       5、列表解析:

       n=4

       my_list=[o]*n#[o,o,o,o]

       6、两个变量之间的交换值:

       original_list=[1,2,3,4]

       newlist=[2*xforxinoriginal_list]

       print(new_list)

       #[2,4,6,8]

       Python经常被用于Web开发。比如,通过mod_wsgi模块,Apache可以运行用Python编写的Web程序。Python定义了WSGI标准应用接口来协调Http服务器与基于Python的Web程序之间的通信。一些Web框架,如Django,TurboGears,web2py,Zope等,可以让程序员轻松地开发和管理复杂的Web程序。

       åœ¨å¾ˆå¤šæ“ä½œç³»ç»Ÿé‡Œï¼ŒPython是标准的系统组件。大多数Linux发行版以及NetBSD、OpenBSD和MacOSX都集成了Python,可以在终端下直接运行Python。

       åº”用范围:

       æœ‰ä¸€äº›Linux发行版的安装器使用Python语言编写,比如Ubuntu的Ubiquity安装器,RedHatLinux和Fedora的Anaconda安装器。

       GentooLinux使用Python来编写它的Portage包管理系统。Python标准库包含了多个调用操作系统功能的库。

       é€šè¿‡pywin这个第三方软件包,Python能够访问Windows的COM服务及其它WindowsAPI。

       ä½¿ç”¨IronPython,Python程序能够直接调用.NetFramework。一般说来,Python编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的shell脚本。

python新手代码有哪些?

       python新手代码有如下:

       defnot_empty(s)。

       returnsandlen(s。strip())0。

       #returnsands。strip()。

       #如果直接单写s。strip()那么s如果是None,会报错,因为None没有strip方法。

       #如果s是None,那么Noneand任何值都是False,直接返回false。

       #如果s非None,那么判定s。trip()是否为空。

       ç›¸å…³ç®€ä»‹ã€‚

       Python解释器易于扩展,可以使用C或C++(或者其他可以通过C调用的语言)扩展新的功能和数据类型。Python也可用于可定制化软件中的扩展程序语言。Python丰富的标准库,提供了适用于各个主要系统平台的源码或机器码。

       å¹´æœˆï¼Œè¯­è¨€æµè¡ŒæŒ‡æ•°çš„编译器Tiobe将Python加冕为最受欢迎的编程语言,年来首次将其置于Java、C和JavaScript之上。