自定义实现插件
自定义插件要实现mybatis的插件接口 Interceptor
public interface Interceptor {
// 执行拦截逻辑的方法
Object intercept(Invocation invocation) throws Throwable;
// 决定是否触发 intercept()方法,如果该插件是拦截对应方法,则返回该类的代理对象
default Object plugin(Object target ) {
return Plugin.wrap(target, this);
}
// 根据配置 初始化 Intercept 对象
default void setProperties(Properties properties) {
// NOP
}
}
自定义拦截器
@Intercepts({
@Signature(
type = Executor.class // 需要拦截的类型
, method = “query” // 需要拦截的方法
// args 中指定 被拦截方法的 参数列表
, args = {MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class}
),
@Signature(
type = Executor.class
, method = “close”
, args = {boolean.class}
)
})
public class MyInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
System.out.println(“被拦截方法执行前打印。。。”);
Object object = invocation.proceed();
System.out.println(“被拦截方法执行后打印。。。”);
return object;
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
}
}
插件配置初始化
插件拦截的4个类:Excutor \ParameterHandler \ StatementHandler\ ResultSetHandler
<plugins>
<plugin interceptor="com.yuz..MyInterceptor ">
<property name="testProp" value="1000"/>
</plugin>
</plugins>
初始化
SqlSessionFactoryBuilder
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 读取配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 解析配置文件得到Configuration对象 创建DefaultSqlSessionFactory对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
XMLConfigBuilder
插件解析:pluginElement(root.evalNode(“plugins”));,最终得到
InterceptorsChain 对象,里面对插件进行管理
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// 对于全局配置文件各种标签的解析
propertiesElement(root.evalNode("properties"));
// 解析 settings 标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 读取文件
loadCustomVfs(settings);
// 日志设置
loadCustomLogImpl(settings);
// 类型别名
typeAliasesElement(root.evalNode("typeAliases"));
// 插件
pluginElement(root.evalNode("plugins"));
// 用于创建对象
objectFactoryElement(root.evalNode("objectFactory"));
// 用于对对象进行加工
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 反射工具箱
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// settings 子标签赋值,默认值就是在这里提供的 >>
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 创建了数据源 >>
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析引用的Mapper映射器
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
InterceptorsChain
public class InterceptorChain {
// 保存所有的 Interceptor 也就我所有的插件是保存在 Interceptors 这个List集合中的
private final List<Interceptor> interceptors = new ArrayList<>();
//根据拦截器集合的拦截配置对某一个对象的进行拦截(反射代理)
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) { // 获取拦截器链中的所有拦截器
target = interceptor.plugin(target); // 创建对应的拦截器的代理对象
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
代理方法的执行 plugin
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 获取当前方法所在类或接口中,可被当前Interceptor拦截的方法
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
// 当前调用的方法需要被拦截 执行拦截操作
return interceptor.intercept(new Invocation(target, method, args));
}
// 不需要拦截 则调用 目标对象中的方法
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
插件的关键类
Interceptor :插件接口,用户自定义插件需要实现该接口
InterceptroChain :插件链管理:应用中所有的插件在初始化节点都会解析放到该对象中进行管理
Plugin :插件触发管理类,负责对插件对象进行代理包装,同时实现invoke调用逻辑,实现多个插件的层层调用
Invocation:调用方法的包装对象,封装调用方法的信息
@Interceptors 拦截的配置注解
@Signature :拦截方法签名注解