再来说说Mybatis的绑定模块。为什么我们在使用Mybatis时只需要写接口和xml文件就可以执行sql?这就是Mybatis的绑定模块要做的事情。今天我们分析一下Mybatis的绑定模块。绑定包下的类主要包括四个MapperRegistry、MapperProxyFactory、MapperProxy和MapperMethod映射注册类。MapperRegistryMapperRegistry是一个注册类,它的knownMappers集合保存了它的addMapper()方法是添加Mapper接口和MapperProxyFactory实例映射关系的方法:publicvoidaddMapper(Classtype){if(type.isInterface()){if(hasMapper(type)){thrownewBindingException("Type"+type+"已为MapperRegistry所知。");}booleanloadCompleted=false;尝试{knownMappers.放(类型,新的MapperProxyFactory<>(类型));//在运行解析器之前添加类型很重要//否则映射器解析器可能会自动尝试绑定。如果类型已知,则不会尝试。MapperAnnotationBuilder解析器=newMapperAnnotationBuilder(config,type);parser.parse();加载完成=真;}finally{if(!loadCompleted){knownMappers.remove(type);}}}}当传入的类型是接口,没有knownMappers时,将类型和对应的MapperProxyFactory实例放入knownMappers中,执行sql时Mybatis会调用MapperRegistry.getMapper()方法@SuppressWarnings("unchecked")publicTgetMapper(Classtype,SqlSessionsqlSession){finalMapperProxyFactorymapperProxyFactory=(MapperProxyFactory)knownMappers.get(type);if(mapperProxyFactory==null){thrownewBindingException("Type"+type+"不为MapperRegistry所知。");}try{returnmapperProxyFactory.newInstance(sqlSession);}catch(Exceptione){thrownewBindingException("获取映射器实例时出错。原因:"+e,e);先从knownMappers集合中找到对应的MapperProxyFactory实例,然后调用newInstance()方法映射工厂类MapperProxyFactoryMapperProxyFactory的代理newInstance()方法:publicTnewInstance(SqlSessionsqlSession){finalMapperProxymapperProxy=newMapperProxy<>(sqlSession,mapperInterface,methodCache);返回新实例(mapperProxy);}@SuppressWarnings("unchecked")protectedTnewInstance(MapperProxymapperProxy){return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{mapperInterface},mapperProxy);}生成mapperInterface接口的代理对象实例。代理类是MapperProxy,它实现了InvocationHandler,使用jdk动态代理生成代理对象,看它重写的invoke()方法:映射代理类MapperProxyMapperProxy的invoke()方法:@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{try{if(Object.class.equals(method.getDeclaringClass())){returnmethod.invoke(this,args);}else{returncachedInvoker(method).invoke(proxy,method,args,sqlSession);}}catch(Throwablet){throwExceptionUtil.unwrapThrowable(t);不是Object的类将被拦截,调用cachedInvoker()方法,其他执行invoke()方法,privateMapperMethodInvokercachedInvoker(Methodmethod)throwsThrowable{try{returnMapUtil.computeIfAbsent(methodCache,method,m->{if(m.isDefault()){try{if(privateLookupInMethod==null){returnnewDefaultMethodInvoker(getMethodHandleJava8(method));}else{returnnewDefaultMethodInvoker(getMethodHandleJava9(method));}}catch(IllegalAccessException|InstantiationException|InvocationTargetException|NoSuchMethodExceptione){抛出新的RuntimeException(e));}}else{returnnewPlainMethodInvoker(newMapperMethod(mapperInterface,method,sqlSession.getConfiguration()));}});}catch(RuntimeExceptionre){Throwablecause=re.getCause();抛出原因==null?回复:原因;}}从methodCache中获取对应的MapperMethodInvoker如果缓存没有,如果是方法是default方法就创建DefaultMethodInvoker对象,否则创建PlainMethodInvoker对象默认方法调用类DefaultMethodInvoker对于DefaultMethodInvoker类通过MethodHandle完成调用privatestaticclassDefaultMethodInvokerimplementsMapperMethodInvoker{privatefinalMethodHandlemethodHandle;publicDefaultMethodInvoker(MethodHandlemethodHandle){super();this.methodHandle=methodHandle;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args,SqlSessionsqlSession)throwsThrowable{returnmethodHandle.bindTo(proxy).invokeWithArguments(args);}}fornormalTheclassPlainMethodInvokercorrespondingtothemethodcompletesthecallthroughMapperMethod,privatestaticclassPlainMethodInvokerimplementsMapperMethodInvoker{privatefinalMapperMethodmapperMethod;publicPlainMethodInvoker(MapperMethodmapperMethod){super();this.mapperMethod=mapperMethodObjectinvoker,}(Methodmethod,Object[]args,SqlSessionsqlSession)throwsThrowable{返回mapperMethod.execute(sqlSession,args);}}小结本文主要介绍Mybatis的绑定模块。它的MapperRegistry存储了Mapper接口和MapperProxyFactory实例的映射关系,MapperProxyFactory是一个工厂。Mapper接口的代理类生成。MapperProxy实现InvocationHandler,重写invoke()方法进行拦截处理,根据方法创建不同的MethodInvoker类判断是否为默认类型,然后调用MapperMethod执行SQL。在下一篇文章中,我们将介绍MapperMethod类。