Две стороны Alipay: почему нельзя перегружать метод отображения в Mybatis?

задняя часть

Автор: Цзу Дацзюнь

来源:my.oschina.net/zudajun/blog/666223

Функция динамического прокси: улучшить целевой метод с помощью обратного вызова метода-перехватчика.

Смысл в том, чтобы улучшить целевой метод. Приведенное выше предложение верно, но не думайте, что это правда.Как всем известно, у динамических агентов также есть гегемония метания хлыста и перекрытия потока, а также научно-фантастический режим, которому даже не нужна цель.

Примечание: по умолчанию в этой статье предполагается, что читатели понимают принцип динамического прокси.Если вы не понимаете значение слова 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);
  }
}

Цель в приведенном выше коде, когда метод в Object.java выполняется, цель указывает на это, и цель становится марионеткой, символом и заполнителем. Когда кнут был перехвачен, цели не было.

Напишите тестовый код:

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());
}

вывод:

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

Это основной принцип реализации автоматического картографа Mybatis Mapper.

Некоторые читатели могут задаться вопросом: как писать код новичку? Нет структуры и нет эстетики.

Нужно сказать, что, будучи опытным мастером, если вы можете писать программы, как новички, вы должны быть мастером среди мастеров. Это может заставить новичков чувствовать себя дружелюбно, комфортно и соответствовать их собственному стилю, так что они или они могут почувствовать, что код, написанный большими коровами, точно такой же, и они даже пишут лучше, чем эти большие коровы, и они полный уверенности с тех пор Энтузиазм высок, думая, что разрыв между ним и Да Ню остался только три минуты.

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();
    }
  }

Маппер выглядит так:

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);

Ответ: нет.

Причина: при броске хлыста и разрыве потока Mybatis использует полное имя пакета+Mapper+method в качестве ключа и переходит к xml, чтобы найти единственный sql для выполнения. Аналогично: key=x.y.UserMapper.getUserById, тогда перегрузка метода вызовет противоречие. Для интерфейса Mapper Mybatis запрещает перегрузку методов (overLoad).

Примечание: При обучении в первую очередь изучается исходный код, и понимается принцип. При написании сообщения в блоге сначала объясните принцип, а затем прочитайте исходный код. Порядок прямо противоположный, надеюсь, читателей это не смутит, думая, что я слишком силен, чтобы быть пророком.