MyBatis基础用法--插件开发

╰半橙微兮° 2023-03-06 10:36 91阅读 0赞

目录

插件简介

插件原理

插件编写

插件示例源码

ExecutorPlugin类

ParameterHandlerPlugin类

ResultSetHandlerPlugin类

StatementHandlerPlugin类


插件简介

MyBatis在四大对象(ExecutorParameterHandlerResultSetHandlerStatementHandler)创建过程中,都会有插件介入,插件可以利用动态代理机制一层层的包装目标对象,从而实现在目标对象执行目标方法之前进行拦截。

MyBatis中,借助于插件我们可以在SQL语句执行过程中的某一点进行拦截调用,这有点类似于Spring中的面向切面编程AOP。

插件原理

MyBatis在创建四大对象(ExecutorParameterHandlerResultSetHandlerStatementHandler)的时候,每一个创建出来的对象并不会被直接返回,而是会对创建好的对象再次调用InterceptorChain.pluginAll(target)方法,该方法会获取到所有的拦截器(Interceptor,所有插件都要实现该接口),并依次调用每一个拦截器的Interceptor.plugin(target)方法为目标对象创建一个代理对象进行返回。这样,通过插件我们可以为四大对象中的每一个都创建出代理对象,从而可以拦截到四大对象执行的方法。

  1. public Object pluginAll(Object target) {
  2. for (Interceptor interceptor : interceptors) {
  3. target = interceptor.plugin(target);
  4. }
  5. return target;
  6. }

默认情况下,MyBatis允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)

插件编写

编写一个MyBatis插件类需要完成以下几个步骤:
1.插件类需实现org.apache.ibatis.plugin.Interceptor接口。
2.使用@Intercepts注解设置插件签名,指定该插件需要拦截哪些类的哪些方法。
3.将编写好的插件类注册到MyBatis的全局配置文件中。

插件示例源码

ExecutorPlugin类

ExecutorPlugin插件用来拦截Executor类的query()方法。

  1. package org.mybatis.plugin;
  2. import java.util.Properties;
  3. import org.apache.ibatis.cache.CacheKey;
  4. import org.apache.ibatis.executor.Executor;
  5. import org.apache.ibatis.mapping.BoundSql;
  6. import org.apache.ibatis.mapping.MappedStatement;
  7. import org.apache.ibatis.plugin.Interceptor;
  8. import org.apache.ibatis.plugin.Intercepts;
  9. import org.apache.ibatis.plugin.Invocation;
  10. import org.apache.ibatis.plugin.Plugin;
  11. import org.apache.ibatis.plugin.Signature;
  12. import org.apache.ibatis.reflection.MetaObject;
  13. import org.apache.ibatis.reflection.SystemMetaObject;
  14. import org.apache.ibatis.session.ResultHandler;
  15. import org.apache.ibatis.session.RowBounds;
  16. @Intercepts({
  17. @Signature(type = Executor.class, method = "query", args = {
  18. MappedStatement.class, Object.class, RowBounds.class,
  19. ResultHandler.class, CacheKey.class, BoundSql.class }),
  20. @Signature(type = Executor.class, method = "query", args = {
  21. MappedStatement.class, Object.class, RowBounds.class,
  22. ResultHandler.class })
  23. })
  24. public class ExecutorPlugin implements Interceptor {
  25. @Override
  26. public Object intercept(Invocation invocation) throws Throwable {
  27. Object target = invocation.getTarget();
  28. System.out.println("所拦截的目标对象-->" + target);
  29. System.out.println("所拦截的目标方法-->" + invocation.getMethod());
  30. System.out.println("所拦截的目标参数-->" + invocation.getArgs());
  31. System.out.println("所拦截的目标类型-->" + invocation.getClass());
  32. // 获取拦截对象的源数据信息
  33. MetaObject metaObject = SystemMetaObject.forObject(target);
  34. /*
  35. * 如果全局配置中cacheEnabled设置为true,获取到的源对象将会是一个CachingExecutor对象
  36. * 需要通过该对象的delegate属性来获取真正的Executor对象
  37. */
  38. // Executor executor=(Executor) metaObject.getValue("delegate");
  39. // System.out.println("获取源对象的delegate属性-->"+executor);
  40. // System.out.println("获取真正Executor对象的configuration属性-->"+metaObject.getValue("delegate.configuration"));
  41. /*
  42. * 实际的Executor对象的真正类型取决于取决于全局配置中defaultExecutorType的设置值
  43. * SIMPLE(默认值)-->SimpleExecutor REUSE-->ReuseExecutor BATCH-->BatchExecutor
  44. */
  45. System.out.println("获取源对象的configuration属性"
  46. + metaObject.getValue("configuration"));
  47. //注意放行,否则将不会执行任何查询操作
  48. Object result = invocation.proceed();
  49. return result;
  50. }
  51. @Override
  52. public Object plugin(Object target) {
  53. // 可以使用Plugin.wrap(target, this)方法,利用当前对象来包装目标对象
  54. Object wrapper = Plugin.wrap(target, this);
  55. return wrapper;
  56. }
  57. @Override
  58. public void setProperties(Properties properties) {
  59. // 在<plugin/>标签中设置的property
  60. System.out.println(properties);
  61. }
  62. }

Center

ParameterHandlerPlugin类

ParameterHandlerPlugin插件用来拦截ParameterHandler类的getParameterObject()setParameters(PreparedStatement ps)方法。

  1. package org.mybatis.plugin;
  2. import java.sql.PreparedStatement;
  3. import java.util.Properties;
  4. import org.apache.ibatis.executor.parameter.ParameterHandler;
  5. import org.apache.ibatis.plugin.Interceptor;
  6. import org.apache.ibatis.plugin.Intercepts;
  7. import org.apache.ibatis.plugin.Invocation;
  8. import org.apache.ibatis.plugin.Plugin;
  9. import org.apache.ibatis.plugin.Signature;
  10. import org.apache.ibatis.reflection.MetaObject;
  11. import org.apache.ibatis.reflection.SystemMetaObject;
  12. @Intercepts({
  13. @Signature(type = ParameterHandler.class, method = "getParameterObject", args = {}),
  14. @Signature(type = ParameterHandler.class, method = "setParameters", args = { PreparedStatement.class })
  15. })
  16. public class ParameterHandlerPlugin implements Interceptor {
  17. @Override
  18. public Object intercept(Invocation invocation) throws Throwable {
  19. Object target = invocation.getTarget();
  20. System.out.println("所拦截的目标对象-->" + target);
  21. System.out.println("所拦截的目标方法-->" + invocation.getMethod());
  22. System.out.println("所拦截的目标参数-->" + invocation.getArgs());
  23. System.out.println("所拦截的目标类型-->" + invocation.getClass());
  24. // 获取目标对象的源数据信息
  25. MetaObject metaObject = SystemMetaObject.forObject(target);
  26. /*
  27. * 获取到的源对象是DefaultParameterHandler类型
  28. */
  29. System.out.println("获取源对象的typeHandlerRegistry属性-->"
  30. + metaObject.getValue("typeHandlerRegistry"));
  31. System.out.println("获取源对象的mappedStatement属性-->"
  32. + metaObject.getValue("mappedStatement"));
  33. System.out.println("获取源对象的parameterObject属性-->"
  34. + metaObject.getValue("parameterObject"));
  35. System.out.println("获取源对象的boundSql属性-->"
  36. + metaObject.getValue("boundSql"));
  37. System.out.println("获取源对象的configuration属性-->"
  38. + metaObject.getValue("configuration"));
  39. // 注意放行,否则将不会执行任何查询操作
  40. Object result = invocation.proceed();
  41. return result;
  42. }
  43. @Override
  44. public Object plugin(Object target) {
  45. // 可以使用Plugin.wrap(target, this)方法,利用当前对象来包装目标对象
  46. Object wrapper = Plugin.wrap(target, this);
  47. return wrapper;
  48. }
  49. @Override
  50. public void setProperties(Properties properties) {
  51. // 在<plugin/>标签中设置的property
  52. System.out.println(properties);
  53. }
  54. }

Center 1

ResultSetHandlerPlugin类

ResultSetHandlerPlugin插件用来拦截ResultSetHandler类的handleResultSets(Statement stmt)方法。

  1. package org.mybatis.plugin;
  2. import java.sql.Statement;
  3. import java.util.Properties;
  4. import org.apache.ibatis.executor.resultset.ResultSetHandler;
  5. import org.apache.ibatis.plugin.Interceptor;
  6. import org.apache.ibatis.plugin.Intercepts;
  7. import org.apache.ibatis.plugin.Invocation;
  8. import org.apache.ibatis.plugin.Plugin;
  9. import org.apache.ibatis.plugin.Signature;
  10. import org.apache.ibatis.reflection.MetaObject;
  11. import org.apache.ibatis.reflection.SystemMetaObject;
  12. @Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class })
  13. })
  14. public class ResultSetHandlerPlugin implements Interceptor {
  15. @Override
  16. public Object intercept(Invocation invocation) throws Throwable {
  17. Object target = invocation.getTarget();
  18. System.out.println("所拦截的目标对象-->" + target);
  19. System.out.println("所拦截的目标方法-->" + invocation.getMethod());
  20. System.out.println("所拦截的目标参数-->" + invocation.getArgs());
  21. System.out.println("所拦截的目标类型-->" + invocation.getClass());
  22. // 获取目标对象的源数据信息
  23. MetaObject metaObject = SystemMetaObject.forObject(target);
  24. /*
  25. * 获取到的源数据对象是DefaultResultSetHandler类型
  26. */
  27. System.out.println("获取源对象的executor属性"
  28. + metaObject.getValue("executor"));
  29. System.out.println("获取源对象的configuration属性"
  30. + metaObject.getValue("configuration"));
  31. System.out.println("获取源对象的objectFactory属性"
  32. + metaObject.getValue("objectFactory"));
  33. System.out.println("获取源对象的typeHandlerRegistry属性"
  34. + metaObject.getValue("typeHandlerRegistry"));
  35. System.out.println("获取源对象的resultSetHandler属性"
  36. + metaObject.getValue("resultHandler"));
  37. System.out.println("获取源对象的parameterHandler属性"
  38. + metaObject.getValue("parameterHandler"));
  39. System.out.println("获取源对象的mappedStatement属性"
  40. + metaObject.getValue("mappedStatement"));
  41. System.out.println("获取源对象的rowBounds属性"
  42. + metaObject.getValue("rowBounds"));
  43. System.out.println("获取源对象的boundSql属性"
  44. + metaObject.getValue("boundSql"));
  45. // 注意放行,否则将不会执行任何查询操作
  46. Object result = invocation.proceed();
  47. return result;
  48. }
  49. @Override
  50. public Object plugin(Object target) {
  51. // 可以使用Plugin.wrap(target, this)方法,利用当前对象来包装目标对象
  52. Object wrapper = Plugin.wrap(target, this);
  53. return wrapper;
  54. }
  55. @Override
  56. public void setProperties(Properties properties) {
  57. // 在<plugin/>标签中设置的property
  58. System.out.println(properties);
  59. }
  60. }

Center 2

StatementHandlerPlugin类

StatementHandlerPlugin插件用来拦截StatementHandler类的query(Statement statement, ResultHandler resultHandler)方法。

  1. package org.mybatis.plugin;
  2. import java.sql.Statement;
  3. import java.util.Properties;
  4. import org.apache.ibatis.executor.statement.StatementHandler;
  5. import org.apache.ibatis.plugin.Interceptor;
  6. import org.apache.ibatis.plugin.Intercepts;
  7. import org.apache.ibatis.plugin.Invocation;
  8. import org.apache.ibatis.plugin.Plugin;
  9. import org.apache.ibatis.plugin.Signature;
  10. import org.apache.ibatis.reflection.MetaObject;
  11. import org.apache.ibatis.reflection.SystemMetaObject;
  12. import org.apache.ibatis.session.ResultHandler;
  13. @Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = {
  14. Statement.class, ResultHandler.class })
  15. })
  16. public class StatementHandlerPlugin implements Interceptor {
  17. @Override
  18. public Object intercept(Invocation invocation) throws Throwable {
  19. Object target = invocation.getTarget();
  20. System.out.println("所拦截的目标对象-->" + target);
  21. System.out.println("所拦截的目标方法-->" + invocation.getMethod());
  22. System.out.println("所拦截的目标参数-->" + invocation.getArgs());
  23. System.out.println("所拦截的目标类型-->" + invocation.getClass());
  24. // 获取目标对象的源数据信息
  25. MetaObject metaObject = SystemMetaObject.forObject(target);
  26. /*
  27. * 获取到的源数据对象是RoutingStatementHandler类型,这是一个包装类,
  28. * 需要通过该对象的delegate属性来获取真正的StatementHandler对象。
  29. * 真正的StatementHandler对象的类型取决于要处理的Statement的类型,
  30. * 而Statement的类型又取决于Mapper中该增删改查标签的statementType属性的设置值:
  31. * PREPARED(默认值)-->PreparedStatement STATEMENT-->Statement
  32. * CALLABLE-->CallableStatement
  33. */
  34. System.out
  35. .println("获取源对象的delegate属性" + metaObject.getValue("delegate"));
  36. System.out.println("获取真正的StatementHandler对象的configuration属性"
  37. + metaObject.getValue("delegate.configuration"));
  38. System.out.println("获取真正的StatementHandler对象的objectFactory属性"
  39. + metaObject.getValue("delegate.objectFactory"));
  40. System.out.println("获取真正的StatementHandler对象的typeHandlerRegistry属性"
  41. + metaObject.getValue("delegate.typeHandlerRegistry"));
  42. System.out.println("获取真正的StatementHandler对象的resultSetHandler属性"
  43. + metaObject.getValue("delegate.resultSetHandler"));
  44. System.out.println("获取真正的StatementHandler对象的parameterHandler属性"
  45. + metaObject.getValue("delegate.parameterHandler"));
  46. System.out.println("获取真正的StatementHandler对象的executor属性"
  47. + metaObject.getValue("delegate.executor"));
  48. System.out.println("获取真正的StatementHandler对象的mappedStatement属性"
  49. + metaObject.getValue("delegate.mappedStatement"));
  50. System.out.println("获取真正的StatementHandler对象的rowBounds属性"
  51. + metaObject.getValue("delegate.rowBounds"));
  52. System.out.println("获取真正的StatementHandler对象的boundSql属性"
  53. + metaObject.getValue("delegate.boundSql"));
  54. // 注意放行,否则将不会执行任何查询操作
  55. Object result = invocation.proceed();
  56. return result;
  57. }
  58. @Override
  59. public Object plugin(Object target) {
  60. // 可以使用Plugin.wrap(target, this)方法,利用当前对象来包装目标对象
  61. Object wrapper = Plugin.wrap(target, this);
  62. return wrapper;
  63. }
  64. @Override
  65. public void setProperties(Properties properties) {
  66. // 在<plugin/>标签中设置的property
  67. System.out.println(properties);
  68. }
  69. }

Center 3

将编写好的插件类注册到MyBatis的全局配置文件中。

  1. <plugins>
  2. <plugin interceptor="org.mybatis.plugin.ParameterHandlerPlugin">
  3. <property name="name" value="root" />
  4. <property name="password" value="123456" />
  5. </plugin>
  6. <plugin interceptor="org.mybatis.plugin.ExecutorPlugin">
  7. </plugin>
  8. <plugin interceptor="org.mybatis.plugin.StatementHandlerPlugin">
  9. </plugin>
  10. <plugin interceptor="org.mybatis.plugin.ResultSetHandlerPlugin">
  11. </plugin>
  12. </plugins>

发表评论

表情:
评论列表 (有 0 条评论,91人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Mybatis开发

    前面几篇文章介绍了Mybtis中四个重要的对象,其中提到它们都是在Configuration中被创建的,我们一起看一下创建四大对象的方法,代码如下所示: public