Mybatis系列二十:插件开发

深碍√TFBOYSˉ_ 2022-02-13 08:55 334阅读 0赞

 MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。
 MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。
 默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
  Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  ParameterHandler (getParameterObject, setParameters)
  ResultSetHandler (handleResultSets, handleOutputParameters)
  StatementHandler (prepare, parameterize, batch, update, query)
一、插件原理:
  在四大对象创建的时候
  1、每个创建出来的对象不是直接返回的,而是
   interceptorChain.pluginAll(parameterHandler);

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

  2、获取到所有的Interceptor(拦截器)(插件需要实现的接口);
    调用interceptor.plugin(target);返回target包装后的对象
  3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)
    我们的插件可以为四大对象创建出代理对象;
    代理对象就可以拦截到四大对象的每一个执行;
在这里插入图片描述
二、编写插件
1、编写插件实现Interceptor接口,并使用 @Intercepts注解完成插件签名

  1. /**
  2. * 完成插件签名:
  3. * 告诉MyBatis当前插件用来拦截哪个对象的哪个方法。
  4. * type:要拦截的四大对象的哪个对象。
  5. * method:要拦截对象的 哪个方法。
  6. * args:要拦截的方法的参数。
  7. */
  8. @Intercepts(
  9. {
  10. @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
  11. })
  12. public class MyFirstPlugin implements Interceptor{
  13. /**
  14. * intercept:拦截:
  15. * 拦截目标对象的目标方法的执行;
  16. */
  17. @Override
  18. public Object intercept(Invocation invocation) throws Throwable {
  19. // TODO Auto-generated method stub
  20. System.out.println("MyFirstPlugin...intercept:"+invocation.getMethod());
  21. //动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
  22. Object target = invocation.getTarget();
  23. System.out.println("当前拦截到的对象:"+target);
  24. //拿到:StatementHandler==>ParameterHandler===>parameterObject
  25. //拿到target的元数据
  26. MetaObject metaObject = SystemMetaObject.forObject(target);
  27. Object value = metaObject.getValue("parameterHandler.parameterObject");
  28. System.out.println("sql语句用的参数是:"+value);
  29. //修改完sql语句要用的参数
  30. metaObject.setValue("parameterHandler.parameterObject", 11);
  31. //执行目标方法
  32. Object proceed = invocation.proceed();
  33. //返回执行后的返回值
  34. return proceed;
  35. }
  36. /**
  37. * plugin:
  38. * 包装目标对象的:包装:为目标对象创建一个代理对象
  39. */
  40. @Override
  41. public Object plugin(Object target) {
  42. // TODO Auto-generated method stub
  43. //我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
  44. System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
  45. Object wrap = Plugin.wrap(target, this);
  46. //返回为当前target创建的动态代理
  47. return wrap;
  48. }
  49. /**
  50. * setProperties:
  51. * 将插件注册时的property属性设置进来
  52. */
  53. @Override
  54. public void setProperties(Properties properties) {
  55. // TODO Auto-generated method stub
  56. System.out.println("插件配置的信息:"+properties);
  57. }
  58. }
  59. @Intercepts(
  60. {
  61. @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
  62. })
  63. public class MySecondPlugin implements Interceptor{
  64. @Override
  65. public Object intercept(Invocation invocation) throws Throwable {
  66. System.out.println("MySecondPlugin...intercept:"+invocation.getMethod());
  67. return invocation.proceed();
  68. }
  69. @Override
  70. public Object plugin(Object target) {
  71. // TODO Auto-generated method stub
  72. System.out.println("MySecondPlugin...plugin:"+target);
  73. return Plugin.wrap(target, this);
  74. }
  75. @Override
  76. public void setProperties(Properties properties) {
  77. // TODO Auto-generated method stub
  78. }
  79. }

2、在全局配置文件中注册插件

  1. <!-- plugins:注册插件 -->
  2. <plugins>
  3. <plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
  4. <property name="username" value="root"/>
  5. <property name="password" value="123456"/>
  6. </plugin>
  7. <plugin interceptor="com.atguigu.mybatis.dao.MySecondPlugin"></plugin>
  8. </plugins>

测试:

  1. @Test
  2. public void test() throws IOException {
  3. String resource = "mybatis-config.xml";
  4. InputStream inputStream = Resources.getResourceAsStream(resource);
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  6. SqlSession openSession = sqlSessionFactory.openSession();
  7. try {
  8. EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
  9. Employee employee = mapper.getEmpById(1);
  10. System.out.println(mapper);
  11. System.out.println(employee);
  12. } finally {
  13. openSession.close();
  14. }
  15. }

在这里插入图片描述

发表评论

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

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

相关阅读

    相关 Mybatis开发

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