这里主要是说动态代理的方式来进行流程的,基本上前三个步骤都是一样的,不会有什么变化,重点在解析配置文件那一步,要知道代理类是什么时候加载的。
// 还是那个parse方法,重点在于 parseConfiguration 里面的 mapperElement 方法private void mapperElement(XNode parent) throws Exception {if (parent != null) {for (XNode child : parent.getChildren()) {if ("package".equals(child.getName())) {String mapperPackage = child.getStringAttribute("name");configuration.addMappers(mapperPackage);}。。。。。// 忽略其它代码}}}// addMappers 找到最终的实现类public <T> void addMapper(Class<T> type) {if (type.isInterface()) {if (hasMapper(type)) {throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<>(type));// It's important that the type is added before the parser is run// otherwise the binding may automatically be attempted by the// mapper parser. If the type is already known, it won't try.MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}// 关于 knowMappers 的声明private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();// 也就是说一个接口对应了一个 MapperProxyFactory
上面是额外说的内容,方面下面获取代理对象的说明
// getMappers 方法继续向下找public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);}public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}// 这里要知道生成代理对象,主要是哪个类的代理,后续执行方法都是执行该类的invoke方法,很明显,是 MapperProxy 代理
invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {return cachedInvoker(method).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}// cachedInvokerprivate MapperMethodInvoker cachedInvoker(Method method) throws Throwable {try {// A workaround for https://bugs.openjdk.java.net/browse/JDK-8161372// It should be removed once the fix is backported to Java 8 or// MyBatis drops Java 8 support. See gh-1929MapperMethodInvoker invoker = methodCache.get(method);if (invoker != null) {return invoker;}return methodCache.computeIfAbsent(method, m -> {if (m.isDefault()) {try {if (privateLookupInMethod == null) {return new DefaultMethodInvoker(getMethodHandleJava8(method));} else {return new DefaultMethodInvoker(getMethodHandleJava9(method));}} catch (IllegalAccessException | InstantiationException | InvocationTargetException| NoSuchMethodException e) {throw new RuntimeException(e);}} else {// 这里是重点return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));}});} catch (RuntimeException re) {Throwable cause = re.getCause();throw cause == null ? re : cause;}}// 最后寻找到 PlainMethodInvoker invoke方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {return mapperMethod.execute(sqlSession, args);}// 最终执行的executor方法public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);if (method.returnsOptional()&& (result == null || !method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName()+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;}
可以看到最后还是执行的是sqlSession的方法。
