1.mybatis插件机制源码解析
2.手写一个简单的有功有功谷歌浏览器拓展插件(附github源码)
3.Vue—关于插件(源码级别的插件分析+实践)
4.IntelliJ IDEA 插件开发指南
5.一文搞懂Mybatis插件原理
6.买了个网站源码怎么用啊?
mybatis插件机制源码解析
引言
本篇源码解析基于MyBatis3.5.8版本。
首先需要说明的源能源是,本篇文章不是码写码写mybatis插件开发的教程,而是插件插件从源码层面分析mybatis是如何支持用户自定义插件开发的。
mybatis的文件插件机制,让其扩展能力大大增加。有功有功论坛源码分享比如我们项目中经常用到的源能源PageHelper,这就是码写码写一款基于mybatis插件能力开发的产品,它的插件插件功能是让基于mybatis的数据库分页查询更容易使用。
当然基于插件我们还可以开发其它功能,文件比如在执行sql前打印日志、有功有功做权限控制等。源能源
正文mybatis插件也叫mybatis拦截器,码写码写它支持从方法级别对mybatis进行拦截。插件插件整体架构图如下:
解释下几个相关概念:
Interceptor拦截器接口,文件用户自定义的拦截器就是实现该接口。
InterceptorChain拦截器链,其内部维护一个interceptorslist,表示拦截器链中所有的拦截器,并提供增加或获取拦截器链的方法。比如有个核心的方法是pluginAll。该方法用来生成代理对象。
Invocation拦截器执行时的上下文环境,其实就是目标方法的调用信息,包含目标对象、调用的方法信息、参数信息。核心方法是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的插件是通过动态代理实现的,那肯定要生成代理对象,生成的逻辑就是前面提到的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方法生成代理对象。有人可能有疑问:如果有多个拦截器,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>1Interceptor接口的intercept方法就是我们自定义拦截器需要实现的逻辑,其参数为Invocation,可从Invocation参数中拿到执行方法的对象,方法,方法参数,比如我们可以从statementHandler拿到SQL语句,实现自己的特殊逻辑。
在该方法的红飘带持股源码结束需要调用invocation#proceed()方法,进行拦截器链的传播。
参考:
blogs.com/chenpi/p/.html
手写一个简单的谷歌浏览器拓展插件(附github源码)
手写谷歌浏览器插件教程:简易实现与代码详解
首先,让我们通过一个直观的示例来启动创建过程。点击浏览器地址栏输入 chrome://extensions/,即可直接访问扩展程序管理界面。 核心配置文件是 manifest.json,这个文件记录了插件的基本信息,如名称、描述、权限等,是插件身份的身份证。 当插件被激活时,用户会看到一个弹出层,这是通过编写 popup.html 来实现的,它包含了一个简单的HTML界面,用于交互或显示信息。 为了保持代码的清晰,我们把相关的脚本逻辑分离到单独的 popup.js 文件中,这样也支持使用 script 标签直接嵌入。在该文件中,我们将实现插件的核心功能。 此外,我们还需要一个辅助文件 inject.js,它的任务是将特定的代码注入到目标网页,实现所需功能,如上图所示。 整个项目的目录结构清晰可见,便于管理和维护。但这里只是基础部分,更多功能的实现和优化将在后续篇章中详细介绍。Vue—关于插件(源码级别的插件分析+实践)
Vue插件的原理基于Vue的`use`方法,该方法接收一个函数或者提供`install`方法的安卓重启源码对象作为参数,如果传入的参数是函数,这个函数会被当作`install`方法。在Vue 2.6.版本中,`use`方法内部使用`initUse`函数给Vue添加了一个静态方法`use`。以vuex为例,它暴露了一个`install`方法,通过`Vue.use(vuex)`来安装插件。vuex的`install`函数会调用`applyMixin`函数,并将Vue传递过去。`applyMixin`函数在Vue 2.x版本中会直接使用`Vue.mixin`来扩展功能,通过在组件的`beforeCreate`钩子中初始化vuex插件。
在Vue中使用混入(mixin)是一种设计模式,可以轻松地被子类继承功能,目的是实现函数复用。Vue中也应用了这一设计模式,通过`Vue.mixin`可以用来分发可复用逻辑。混入可以分为全局混入和局部混入,全局混入会影响所有的Vue实例,如果组件中与mixin中具有同名的属性,会进行选项合并,除了生命周期外,其它的所有属性都会被组件自身的属性覆盖。使用混入可以节省代码量,类似于类继承。
要自己实现一个提示框插件,可以通过`this.$notify()`进行调用,并且可以传入自定义模板。创建一个Vue工程,在`src`目录下新建`plugin`目录,然后创建一个`notify`目录,新建`index.js`和`Notify.vue`。在`index.js`中,引入`Notify.vue`组件,并通过`install`方法中注入的Vue来完成功能。实例挂载之后才可以访问`$el`选项,可以通过`Vue.use`来使用插件,然后在App.vue中验证功能是否正常。要实现传入模板并且显示出来,可以通过`$mount` API手动挂载一个实例,并在调用`$notify`方法时将挂载的元素插入到文档中。通过创建Vue组件,将DOM、JS、Style都创建好,最后调用`$notify`方法将组件插入到页面中。要实现传入模板,可以使用`v-html`指令来插入模板,并在Notify.vue中新增接收参数的方法。在App.vue中传递一段模板,页面上操作的效果为显示提示框,两秒后消失。
IntelliJ IDEA 插件开发指南
年,面对IntelliJ全家桶的使用,是否还有人质疑其效能? 公司Terminus自研的框架Trantor催生了我们开发插件的需求,为了更好地整合其项目结构和特性,我们希望为IDEA用户打造一个便捷的插件支持。在我的GitHub上,不断更新的示例代码展示了插件的一些功能实现。功能概述
...
踏入插件世界
插件开发主要分为几个类别:技术栈
开发IntelliJ插件所需的技术包括:创建插件
官方提供了以下指导:新建项目
项目基本结构,如plugin.xml配置文件
核心工具:PSI
PSI是程序结构接口,用于解析文件、构建语法和语义代码。IDEA内置许多插件,允许开发者操作工程元素,自定义语言开发则需实现Parser等。PsiFile详解
PsiFile是文件结构的基石,代表文件内容的语法结构。例如,Java文件对应PsiJavaFile,XML文件对应XmlFile。探索PSI结构
掌握View PSI结构工具,如Tools > View PSI Structure of Current File,通过Gradle:runIde沙箱来探索代码对应的复杂PSI元素。常用API与操作
插件开发涉及众多API,有些方法需要猜测或通过搜索找到。对PsiElement的写操作务必在writeAction上下文中进行。虚拟文件与转换
虚拟文件(VF)代表IntelliJ中的文件,与PsiFile间可通过Action转换。行动组件
使用com.intellij.openapi.actionSystem.AnAction创建并注册动作,例如在plugin.xml中定义。服务管理
利用ServiceManager获取服务实例,如ProjectService。Light Services在.3之后更加便捷,但需要注意一些限制。插件界面
IntelliJ提供了对话框组件、Swing UI Designer、EditorTextField等,以及UI检查器工具。Gradle插件
从Gradle IDEA插件的运行、调试,到构建和打包,都有相应的指导和工具。发布选项
官方提供了发布到JetBrains插件库和自定义存储库的方法,详细步骤需在build.gradle中配置。学习资源
深入学习IntelliJ IDEA官方文档、参考开源插件和社区,以及IDEA源码,是插件开发不可或缺的资源。 期待你的提问和交流,一起探索IntelliJ IDEA插件开发的无限可能。一文搞懂Mybatis插件原理
Mybatis插件原理详解,让你轻松实现自定义功能
在深入Mybatis源码时,你可能会遇到名为"plugin"的包,这实际上用于扩展框架的功能,如PageHelper分页插件。本文将揭示插件的运作机制,教你如何理解其内部工作并自行实现,如分页或慢SQL统计。
使用PageHelper插件分页的简单步骤是:一,在pom.xml中添加依赖;二,在mybatis-config.xml中配置插件;三,在需要分页的mapper接口前调用startPage方法,并确保每次查询后关闭Page对象以避免数据冲突。
接下来,我们将探索插件的总体流程:首先,通过拦截器接口实现动态代理,如PageInterceptor,它会在Executor的query方法执行前后添加自定义逻辑。拦截器通过Invocation对象获取目标对象和方法参数,实现增强功能。
分页拦截器如PageInterceptor拦截query方法,若需要分页,会获取原始SQL并添加limit语句。配置插件时,在mybatis-config.xml中添加相应拦截器,如``标签和Interceptor实现类的全限定名。
当我们创建SqlSession时,拦截器通过Configuration的newExecutor方法注册并应用到Executor对象上,利用JDK动态代理生成增强的代理对象,从而在执行SQL时调用拦截器的intercept方法。
自定义慢SQL统计插件同样基于Interceptor,只需配置目标对象为StatementHandler,拦截方法为query、update或batch,然后在配置文件中添加插件的全限定名。
买了个网站源码怎么用啊?
买了个网站源码后的使用方法如下: 1、申请域名 要访问一个网站,必须要输入域名,域名相当于这个网站的门牌号,没有域名是无法找到和访问网站的,因此必须找域名提供商家,购买域名。 2、购买网站空间 有了域名,还要有网站空间用来存放你的网站源码,网上提供网站存放空间的服务商有很多,可以根据你的网站源码代码和需要的容量选择购买合适的空间。 3、上传网站源码 有了网站空间后,就可以根据服务商提供的信息登录网站后台,然后将自己的网站源码上传到相应的目录。 4、绑定域名 然后给自己的网站绑定前面申请购买的域名,这样你的网站就可以使用了。 5、分享网站 把你的网站域名分享给别人,别人就可以通过域名来访问你的网站了。买了个网站源码后要怎么用
1. 购买网站源码后,首先需要将其上传至服务器。使用FTP或其他文件传输工具将源码文件从本地计算机传输到服务器上。
2. 上传完成后,确保服务器已配置好必要的环境,如Web服务器(如Apache或Nginx)和数据库(如MySQL或PostgreSQL)。
3. 对网站源码进行配置,包括设置数据库连接、调整网站基本参数以及外观和功能上的个性化设置。根据源码类型,可能需要参考文档或联系开发者进行配置。
4. 随后,根据个人需求和技能水平,定制网站的内容和外观。这可能涉及编辑页面内容、调整布局和样式、添加功能插件或模块等。
5. 完成所有配置和定制工作后,进行充分测试,确保网站功能和性能均无问题。
6. 测试通过后,将网站上线,通过域名解析让网站正式对外运营。
7. 注意,不同网站源码可能有特定的安装和配置要求。操作前应仔细阅读相关文档或咨询开发者,确保按照正确步骤进行。
8. 对于无相关经验的人来说,可能需要学习和实践来熟悉网站的配置和定制过程。