动态代理的功能:通过拦截器方法回调,对目标target方法进行增强。

言外之意就是为了增强目标target方法。上面这句话没错,但也不要认为它就是真理,殊不知,动态代理还有投鞭断流的霸权,连目标target都不要的科幻模式。

注:本文默认认为,读者对动态代理的原理是理解的,如果不明白target的含义,难以看懂本篇文章,建议先理解动态代理。

1. 自定义JDK动态代理之投鞭断流实现自动映射器Mapper

首先定义一个pojo。

public class User {
  private Integer id;
  private String name;
  private int age;

  public User(Integer id, String name, int age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
  // getter setter
}

再定义一个接口UserMapper.java。

public interface UserMapper {
  public User getUserById(Integer id);  
}

接下来我们看看如何使用动态代理之投鞭断流,实现实例化接口并调用接口方法返回数据的。

自定义一个InvocationHandler。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MapperProxy implements InvocationHandler {

  @SuppressWarnings("unchecked")
  public <T> T newInstance(Class<T> clz) {
    return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this);
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        // 诸如hashCode()、toString()、equals()等方法,将target指向当前对象this
        return method.invoke(this, args);
      } catch (Throwable t) {
      }
    }
    // 投鞭断流
    return new User((Integer) args[0], "zhangsan", 18);
  }
}

上面代码中的target,在执行Object.java内的方法时,target被指向了this,target已经变成了傀儡、象征、占位符。在投鞭断流式的拦截时,已经没有了target。

写一个测试代码:


public static void main(String[] args) {
  MapperProxy proxy = new MapperProxy();

  UserMapper mapper = proxy.newInstance(UserMapper.class);
  User user = mapper.getUserById(1001);

  System.out.println("ID:" + user.getId());
  System.out.println("Name:" + user.getName());
  System.out.println("Age:" + user.getAge());

  System.out.println(mapper.toString());
}

output:

ID:1001
Name:zhangsan
Age:18
x.y.MapperProxy@6bc7c054

这便是Mybatis自动映射器Mapper的底层实现原理。

可能有读者不禁要问:你怎么把代码写的像初学者写的一样?没有结构,且缺乏美感。

必须声明,作为一名经验老道的高手,能把程序写的像初学者写的一样,那必定是高手中的高手。这样可以让初学者感觉到亲切,舒服,符合自己的Style,让他们或她们,感觉到大牛写的代码也不过如此,自己甚至写的比这些大牛写的还要好,从此自信满满,热情高涨,认为与大牛之间的差距,仅剩下三分钟。

2. Mybatis自动映射器Mapper的源码分析

首先编写一个测试类:

public static void main(String[] args) {
    SqlSession sqlSession = MybatisSqlSessionFactory.openSession();
    try {
      StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
      List<Student> students = studentMapper.findAllStudents();
      for (Student student : students) {
        System.out.println(student);
      }
    } finally {
      sqlSession.close();
    }
  }

Mapper长这个样子:


public interface StudentMapper {
  List<Student> findAllStudents();
  Student findStudentById(Integer id);
  void insertStudent(Student student);
}

org.apache.ibatis.binding.MapperProxy.java部分源码。

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    // 投鞭断流
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
  // ...

org.apache.ibatis.binding.MapperProxyFactory.java部分源码。

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

这便是Mybatis使用动态代理之投鞭断流。

3. 接口Mapper内的方法能重载(overLoad)吗?(重要)

类似下面:

public User getUserById(Integer id);
public User getUserById(Integer id, String name);

Answer:不能。

原因:在投鞭断流时,Mybatis使用package+Mapper+method全限名作为key,去xml内寻找唯一sql来执行的。

类似:key=x.y.UserMapper.getUserById,那么,重载方法时将导致矛盾。对于Mapper接口,Mybatis禁止方法重载(overLoad)。

Mybatis接口Mapper内的方法为啥不能重载吗?的更多相关文章

  1. Mybatis的Mapper中的方法为什么不能重载?

    目录 前言 环境配置 错误示范 为什么不能重载? 如何找到XML中对应的SQL? 总结 前言 在初入门Mybatis的时候可能都犯过一个错误,那就是在写Mapper接口的时候都重载过其中的方法,但是运 ...

  2. Mybatis的mapper代理开发方法

    一.开发规范 1.映射文件中的namespase等于mapper接口类路径 2.statement的id与mapper中的方法名一致 3.让mapper的接口方法输入参数类型与statement中的p ...

  3. Mybatis的Mapper接口方法不能重载

    今天给项目的数据字典查询添加通用方法,发现里边已经有了一个查询所有数据字典的方法 List<Dict> selectDictList(); 但我想设置的方法是根据数据字典的code查询出所 ...

  4. mybatis如何通过接口查找对应的mapper.xml及方法执行详解

    转:http://www.jb51.net/article/116402.htm 本文主要介绍的是关于mybatis通过接口查找对应mapper.xml及方法执行的相关内容,下面话不多说,来看看详细的 ...

  5. Mybatis的mapper接口接受的参数类型

    最近项目用到了Mybatis,学一下记下来. Mybatis的Mapper文件中的select.insert.update.delete元素中有一个parameterType属性,用于对应的mappe ...

  6. Mybatis的mapper代理开发dao方法

    看完了之前的mybatis原始的dao开发方法是不是觉得有点笨重,甚至说没有发挥mybatis 作为一个框架的优势.总结了一下,原始的dao方法有以下几点不足之处 dao接口实现方法中存在大量的模板方 ...

  7. mybatis的mapper接口代理使用的三个规范

    1.什么是mapper代理接口方式? MyBatis之mapper代理方式.mapper代理使用的是JDK的动态代理策略 2.使用mapper代理方式有什么好处 使用这种方式可以不用写接口的实现类,免 ...

  8. mybatis由浅入深day01_5.3 Mapper动态代理方法

    5.3 Mapper动态代理方法(程序员只需要写mapper接口(相当于dao接口)) 5.3.1 实现原理(mapper代理开发规范) 程序员还需要编写mapper.xml映射文件 程序员编写map ...

  9. Mybatis框架 使用接口Mapper实现数据库的crud操作

    Mybatis的Mapper接口方式实现简单crud操作: 1.创建实体类 与数据库对应 我的实体类是<Student>   package com.hxzy.mybatis.pojo; ...

随机推荐

  1. 2.MongoDB 4.2副本集环境基于时间点的恢复

    (一)MongoDB恢复概述 对于任何数据库,如果要将数据库恢复到过去的任意时间点,否需要有过去某个时间点的全备+全备之后的重做日志. 接下来根据瑞丽航空的情况进行概述: 全备:每天晚上都会进行备份: ...

  2. C语言文件读写命令fprintf和fscanf

    以向文件中读取和写入二维数组为例. 以下是fprintf的使用:向文件中写入10*10的二维数组,数组元素为1~100之间的随机数. #include <stdlib.h> #includ ...

  3. Android Studio gridview 控件使用自定义Adapter, 九宫格items自适应全屏显示

    先看效果图,类似于支付宝首页的效果.由于九宫格显示的帖子网上已经很多,但是像这样九宫格全屏显示的例子还不是太多.本实例的需求是九宫格全屏显示,每个子view的高度是根据全屏高度三等分之后自适应高度,每 ...

  4. JavaScript设计模式之命令模式【命令解耦】

    在讲解命令模式之前我们先来了解一个生活中的命令模式场景: 场景1: 医院看病抓药: 当你因为肾虚到医院看医生,医生一番操作之后得出结论:要吃个疗程[夏桑菊].[小柴胡](药名纯属虚构,真的肾虚就找医生 ...

  5. 七脚OLED屏幕使用IIC接口

    7pin 0.96寸OLED模块支持SPI和IIC接口 默认是SPI接口;如果想用IC接口;操作如下几步骤: 1.将模块背面的电阻R3换到R1位置,此时将模块切换为IIC接口:电阻R8可以用0欧姆电阻 ...

  6. C言语--冒泡排序

    /* 冒泡排序,从小到大 */ include<stdio.h> int main(void) { int i; int t; int p; int val; int a[6]; for( ...

  7. TX-LCN 分布式事务框架

    第十章 TX-LCN 分布式事务框架 (Spring Cloud 高级) 一. 什么是分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位 于不同的分布式系统的不同 ...

  8. 开启gzip压缩/cdn是否会影响抓取和收录量

    http://www.wocaoseo.com/thread-291-1-1.html 服务器开启gzip压缩是否会影响蜘蛛抓取和收录量?站点开了CDN,对百度SEO影响有多大?我发现我们站自从开了C ...

  9. Canalv1.1.4版本搭建HA集群

    前提 Canal上一个正式版是于2019-9-2发布的v1.1.4,笔者几个月前把这个版本的Canal推上了生产环境,部署了HA集群.过程中虽然遇到不少的坑,但是在不出问题的前提下,Canal的作用还 ...

  10. Redux异步解决方案之Redux-Thunk原理及源码解析

    前段时间,我们写了一篇Redux源码分析的文章,也分析了跟React连接的库React-Redux的源码实现.但是在Redux的生态中还有一个很重要的部分没有涉及到,那就是Redux的异步解决方案.本 ...