支付宝二面:MybatisインタフェースMapper内の方法はなぜ再ロードできないのですか?私は直接呆然とした...


ダイナミックエージェントの機能:ブロッキングメソッドコールバックにより、ターゲットtargetメソッドを強化します.
言外の意味は、ターゲットターゲットターゲットメソッドを強化するためです.上の言葉は間違いないが、それが真理だとは思わないでください.意外にも、ダイナミックエージェントには鞭を打つ覇権があり、目標targetさえいらないSFモデルがあります.
注意:本稿では、読者がダイナミックエージェントの原理を理解しているとデフォルトで考えられていますが、targetの意味が分からなければ、この文章を理解するのは難しいので、まずダイナミックエージェントを理解することをお勧めします.
1.カスタムJDKダイナミックエージェントの鞭打ち断流実現自動マッパーマッパー
まず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
}

インタフェースをもう一つ定義します.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 newInstance(Class 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オートマッパの最下層実装原理である.初心者のようにコードを書くのはどうですか?構造がなく、美感に欠けている.
経験のあるベテランとして、初心者が書いたようにプログラムを書くことができるのは、必ず達人の中の達人だと宣言しなければならない.このように初心者に亲切さを感じさせることができて、心地よくて、自分のStyleに合って、彼らあるいは彼女たちに、大牛が书いたコードを感じさせるのもただこのようにして、自分は甚だしきに至ってはこれらの大牛が书いたよりも良くて、それから自信がいっぱいで、情热が高まって、大牛との间の差距、3分しか残っていないと思っています.
2.Mybatis自動マッパーMapperのソースコード分析
まず、テストクラスを作成します.
public static void main(String[] args) {
    SqlSession sqlSession = MybatisSqlSessionFactory.openSession();
    try {
      StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
      List students = studentMapper.findAllStudents();
      for (Student student : students) {
        System.out.println(student);
      }
    } finally {
      sqlSession.close();
    }
  }

Mapperはこのように成長しています.
public interface StudentMapper {
  List findAllStudents();
  Student findStudentById(Integer id);
  void insertStudent(Student student);
}
org.apache.ibatis.binding.MapperProxy.java    。
public class MapperProxy implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class mapperInterface;
  private final Map methodCache;

  public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map 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 {

  private final Class mapperInterface;

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy 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はメソッドの再ロードを禁止します.
注:勉強するときは、先に研究したソースコードで、原理がわかりました.博文を書くときは、まず原理を解釈してから、ソースコードを読みます.順序は正反対で、読者が私が預言者を知らないほど強いと疑わないでほしい.