标签:inter line 代理 自身 简单 tar ext 结构 throwable
本文,我们来分享 MyBatis 的插件模块,对应 plugin
包。如下图所示:
在 《精尽 MyBatis 源码解析 —— 项目结构一览》 中,简单介绍了这个模块如下:
Mybatis 自身的功能虽然强大,但是并不能完美切合所有的应用场景,因此 MyBatis 提供了插件接口,我们可以通过添加用户自定义插件的方式对 MyBatis 进行扩展。用户自定义插件也可以改变 Mybatis 的默认行为,例如,我们可以拦截 SQL 语句并对其进行重写。
由于用户自定义插件会影响 MyBatis 的核心行为,在使用自定义插件之前,开发人员需要了解 MyBatis 内部的原理,这样才能编写出安全、高效的插件。
本文涉及的类如下图所示:
下面,我们逐个类来瞅瞅。
org.apache.ibatis.plugin.Interceptor
,拦截器接口。代码如下:
// Interceptor.java
|
我们来看看 org.apache.ibatis.plugin.PluginTest
,提供了 AlwaysMapPlugin 示例。代码如下:
|
<1>
处,通过 @Intercepts
和 @Signature
注解,定义了需要拦截的方法为 Map 类型、方法为 "get"
方法,方法参数为 Object.class
。详细解析,见 TODO。<2>
处,在实现方法 #plugin(Object target)
方法内部,他调用 Plugin#wrap(Object target, Interceptor interceptor)
方法,执行代理对象的创建。详细解析,见 TODO。<3>
处,在实现方法 #setProperties(Properties properties)
方法内部,暂未做任何实现。此处可以实现,若 AlwaysMapPlugin 有属性,可以从 properties
获取一些需要的属性值。<4>
处,在实现方法 #intercept(Invocation invocation)
方法,直接返回 "Always"
字符串。也就是说,当所有的 target
类型为 Map 类型,并且调用 Map#get(Object)
方法时,返回的都是 "Always"
。这个示例,胖友可以跑下 PluginTest 单元测试里的方法,可以更加好理解。
org.apache.ibatis.plugin.Invocation
,方法调用信息,作为 Interceptor#intercept(Invocation invocation)
的方法参数。代码如下:
// Invocation.java
|
org.apache.ibatis.plugin.InterceptorChain
,拦截器 Interceptor 链。
// InterceptorChain.java
|
#addInterceptor(Interceptor interceptor)
方法,添加拦截器。代码如下:
// InterceptorChain.java
|
该方法在 Configuration 的 #pluginElement(XNode parent)
方法中被调用,代码如下:
// XMLConfigBuilder.java
|
<1>
处,创建 Interceptor 对象,并调用 Interceptor#setProperties(properties)
方法,设置拦截器的属性。<2>
处,调用 Configuration#addInterceptor(interceptorInstance)
方法,添加到 Configuration.interceptorChain
中。代码如下:
// Configuration.java
|
#pluginAll(Object target)
方法,应用所有拦截器到指定目标对象。代码如下:
// InterceptorChain.java
|
该方法被 Configuration 的如下四处方法中调用:
org.apache.ibatis.plugin.@Intercepts
,拦截器注解。代码如下:
// Intercepts.java
|
org.apache.ibatis.plugin.@Signature
,方法签名的注解。代码如下:
// Signature.java
|
org.apache.ibatis.plugin.Plugin
,实现 InvocationHandler 接口,插件类,一方面提供创建动态代理对象的方法,另一方面实现对指定类的指定方法的拦截处理。
注意,Plugin 是 MyBatis 插件体系的核心类。
// Plugin.java
|
#wrap(Object target, Interceptor interceptor)
静态方法,创建目标类的代理对象。代码如下:
// Plugin.java
|
<1>
处,调用 #getSignatureMap(Interceptor interceptor)
方法,获得拦截的方法映射。代码如下:
// Plugin.java
|
@Intercepts
和 @Signature
注解。<2>
处,调用 #getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap)
方法,获得目标类的接口集合。代码如下:
// Plugin.java
|
@Signature
注解的 type
属性,必须是接口。<3.1>
处,情况一,若有接口,则创建目标对象的 JDK Proxy 对象。<3.2>
处,情况二,若无接口,则返回原始的目标对象。
// Plugin.java
|
标签:inter line 代理 自身 简单 tar ext 结构 throwable
原文地址:https://www.cnblogs.com/siye1989/p/11624505.html