这里主要是说动态代理的方式来进行流程的,基本上前三个步骤都是一样的,不会有什么变化,重点在解析配置文件那一步,要知道代理类是什么时候加载的。

  1. // 还是那个parse方法,重点在于 parseConfiguration 里面的 mapperElement 方法
  2. private void mapperElement(XNode parent) throws Exception {
  3. if (parent != null) {
  4. for (XNode child : parent.getChildren()) {
  5. if ("package".equals(child.getName())) {
  6. String mapperPackage = child.getStringAttribute("name");
  7. configuration.addMappers(mapperPackage);
  8. }
  9. 。。。。。// 忽略其它代码
  10. }
  11. }
  12. }
  13. // addMappers 找到最终的实现类
  14. public <T> void addMapper(Class<T> type) {
  15. if (type.isInterface()) {
  16. if (hasMapper(type)) {
  17. throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
  18. }
  19. boolean loadCompleted = false;
  20. try {
  21. knownMappers.put(type, new MapperProxyFactory<>(type));
  22. // It's important that the type is added before the parser is run
  23. // otherwise the binding may automatically be attempted by the
  24. // mapper parser. If the type is already known, it won't try.
  25. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
  26. parser.parse();
  27. loadCompleted = true;
  28. } finally {
  29. if (!loadCompleted) {
  30. knownMappers.remove(type);
  31. }
  32. }
  33. }
  34. }
  35. // 关于 knowMappers 的声明
  36. private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
  37. // 也就是说一个接口对应了一个 MapperProxyFactory

上面是额外说的内容,方面下面获取代理对象的说明

  1. // getMappers 方法继续向下找
  2. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  3. return mapperRegistry.getMapper(type, sqlSession);
  4. }
  5. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  6. final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  7. if (mapperProxyFactory == null) {
  8. throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  9. }
  10. try {
  11. return mapperProxyFactory.newInstance(sqlSession);
  12. } catch (Exception e) {
  13. throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  14. }
  15. }
  16. protected T newInstance(MapperProxy<T> mapperProxy) {
  17. return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  18. }
  19. public T newInstance(SqlSession sqlSession) {
  20. final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  21. return newInstance(mapperProxy);
  22. }
  23. // 这里要知道生成代理对象,主要是哪个类的代理,后续执行方法都是执行该类的invoke方法,很明显,是 MapperProxy 代理

invoke方法

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2. try {
  3. if (Object.class.equals(method.getDeclaringClass())) {
  4. return method.invoke(this, args);
  5. } else {
  6. return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
  7. }
  8. } catch (Throwable t) {
  9. throw ExceptionUtil.unwrapThrowable(t);
  10. }
  11. }
  12. // cachedInvoker
  13. private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  14. try {
  15. // A workaround for https://bugs.openjdk.java.net/browse/JDK-8161372
  16. // It should be removed once the fix is backported to Java 8 or
  17. // MyBatis drops Java 8 support. See gh-1929
  18. MapperMethodInvoker invoker = methodCache.get(method);
  19. if (invoker != null) {
  20. return invoker;
  21. }
  22. return methodCache.computeIfAbsent(method, m -> {
  23. if (m.isDefault()) {
  24. try {
  25. if (privateLookupInMethod == null) {
  26. return new DefaultMethodInvoker(getMethodHandleJava8(method));
  27. } else {
  28. return new DefaultMethodInvoker(getMethodHandleJava9(method));
  29. }
  30. } catch (IllegalAccessException | InstantiationException | InvocationTargetException
  31. | NoSuchMethodException e) {
  32. throw new RuntimeException(e);
  33. }
  34. } else {
  35. // 这里是重点
  36. return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  37. }
  38. });
  39. } catch (RuntimeException re) {
  40. Throwable cause = re.getCause();
  41. throw cause == null ? re : cause;
  42. }
  43. }
  44. // 最后寻找到 PlainMethodInvoker invoke方法
  45. @Override
  46. public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  47. return mapperMethod.execute(sqlSession, args);
  48. }
  49. // 最终执行的executor方法
  50. public Object execute(SqlSession sqlSession, Object[] args) {
  51. Object result;
  52. switch (command.getType()) {
  53. case INSERT: {
  54. Object param = method.convertArgsToSqlCommandParam(args);
  55. result = rowCountResult(sqlSession.insert(command.getName(), param));
  56. break;
  57. }
  58. case UPDATE: {
  59. Object param = method.convertArgsToSqlCommandParam(args);
  60. result = rowCountResult(sqlSession.update(command.getName(), param));
  61. break;
  62. }
  63. case DELETE: {
  64. Object param = method.convertArgsToSqlCommandParam(args);
  65. result = rowCountResult(sqlSession.delete(command.getName(), param));
  66. break;
  67. }
  68. case SELECT:
  69. if (method.returnsVoid() && method.hasResultHandler()) {
  70. executeWithResultHandler(sqlSession, args);
  71. result = null;
  72. } else if (method.returnsMany()) {
  73. result = executeForMany(sqlSession, args);
  74. } else if (method.returnsMap()) {
  75. result = executeForMap(sqlSession, args);
  76. } else if (method.returnsCursor()) {
  77. result = executeForCursor(sqlSession, args);
  78. } else {
  79. Object param = method.convertArgsToSqlCommandParam(args);
  80. result = sqlSession.selectOne(command.getName(), param);
  81. if (method.returnsOptional()
  82. && (result == null || !method.getReturnType().equals(result.getClass()))) {
  83. result = Optional.ofNullable(result);
  84. }
  85. }
  86. break;
  87. case FLUSH:
  88. result = sqlSession.flushStatements();
  89. break;
  90. default:
  91. throw new BindingException("Unknown execution method for: " + command.getName());
  92. }
  93. if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  94. throw new BindingException("Mapper method '" + command.getName()
  95. + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  96. }
  97. return result;
  98. }

可以看到最后还是执行的是sqlSession的方法。