springboot-mybatis 整合了 mybatis 对数据库的拜访操,其为我做了很好的封装,开箱即用。只有在我的项目中引入 maven的依赖,打上 MapperScan 的注解就能够进入咱们的业务开发。
咱们从注解 MapperScan 动手查看,可知在这个注解用 @Import 在容器中注册了一个 MapperScannerRegistrar 的bean。该类实现了 ImportBeanDefinitionRegistrar 接口,重写了registerBeanDefinitions 办法:
**1.** @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 获取打了 MapperScan 注解的类上的注解信息,包含 basePackages 等信息,这里即便dao包里的接口没有打 Component 注解也会被注入到容器中。 AnnotationAttributes mapperScanAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); if (mapperScanAttrs != null) { registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0)); } }
获取到注解信息之后,进入其本身的 registerBeanDefinitions 办法:
**2.** void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { // new 了一个 BeanDefinitionBuilder 对象并将其 beanClass 设置为 MapperScannerConfigurer.class。 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); // 上面都是一些属性的设置 Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); if (!Annotation.class.equals(annotationClass)) { builder.addPropertyValue("annotationClass", annotationClass); } Class<?> markerInterface = annoAttrs.getClass("markerInterface"); if (!Class.class.equals(markerInterface)) { builder.addPropertyValue("markerInterface", markerInterface); } Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); if (!BeanNameGenerator.class.equals(generatorClass)) { builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass)); } Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); } String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef"); if (StringUtils.hasText(sqlSessionTemplateRef)) { builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef")); } String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef"); if (StringUtils.hasText(sqlSessionFactoryRef)) { builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")); } List<String> basePackages = new ArrayList<>(); basePackages.addAll( Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList())); basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText) .collect(Collectors.toList())); basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName) .collect(Collectors.toList())); if (basePackages.isEmpty()) { basePackages.add(getDefaultBasePackage(annoMeta)); } String lazyInitialization = annoAttrs.getString("lazyInitialization"); if (StringUtils.hasText(lazyInitialization)) { builder.addPropertyValue("lazyInitialization", lazyInitialization); } // 在builder 中设置 basePackage 属性 builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)); // 向容器中注册了一个 MapperScannerConfigurer 的bean。 registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); }
通过下面的代码逻辑咱们可知,MapperScannerRegistrar 向容器中注册了一个 MapperScannerConfigurer 的bean。而该类实现了 BeanDefinitionRegistryPostProcessor 接口,查看其 postProcessBeanDefinitionRegistry 办法,在该办法中实现了对 basePackages 包下的 dao 接口文件的解析包装成 bean。
**3.** public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } // 创立了一个 ClassPathMapperScanner 用于解析 mapper.xml 文件,上面是一些属性设置。 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); scanner.setAnnotationClass(this.annotationClass); scanner.setMarkerInterface(this.markerInterface); scanner.setSqlSessionFactory(this.sqlSessionFactory); scanner.setSqlSessionTemplate(this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); if (StringUtils.hasText(lazyInitialization)) { scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); } // scanner 外面设置过滤器,增加默认的 includeFilters 和 excludeFilters scanner.registerFilters(); // 这里是真正的解析 mapper.xml 文件,生成各个 MapperedStatement 对象保留至 Configuration 中。 scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
跟进 scanner 的 scan 办法到 ClassPathMapperScanner 的doScan 办法:
**4.**public Set<BeanDefinitionHolder> doScan(String... basePackages) { // 调用父类的 doScan 办法,父类是 spring 的类,和 mybatis 没有关系,返回的是一个类型为 BeanDefinition 的 set。 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 这里为beanDefinition 设置属性相干的信息。(**5.**) processBeanDefinitions(beanDefinitions); } return beanDefinitions;}
**5.** private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); String beanClassName = definition.getBeanClassName(); LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface"); definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // 这里设置 beanClass 为 MapperFactoryBean,之后实例化调用的是这个类的结构器。这个很要害-。- definition.setBeanClass(this.mapperFactoryBeanClass); definition.getPropertyValues().add("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false; if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionFactory != null) { definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true; } if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { LOGGER.warn( () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { LOGGER.warn( () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } definition.setLazyInit(lazyInitialization); } }
到这里的 beanDefinition 的创立及属性设置根本结束,接下来是 bean 的创立。spring bean 实例化之后,调用populateBean 办法设置属性,其中有个autowireByType 办法 对属性从新获取,并通过 setter 办法,将 sqlSessionTemplate 作为属性注入。而这个 sqlSessionTemplate 蕴含了 mapper.xml 文件的解析后果,前期须要执行的 sql 都在这里。接下来咱们须要晓得这个 sqlSessionTemplate bean 是如何被创立的。
咱们查看 mybatis 的主动配置类 MybatisAutoConfiguration 其的两个办法:sqlSessionFactory 和 sqlSessionTemplate 别离向容器中注入了 sqlSessionFactory 和 SqlSessionTemplate 的 bean。提供了咱们自定义的 dao 中这两个属性的注入。咱们先看 sqlSessionFactory 办法,SqlSessionTemplate 办法只不过是将 sqlSessionFactory 作为参数传入并 new 了一个 SqlSessionTemplate 的 bean。
**6.** public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } // 这里其实是新建了一个 Configuration 对象,前面的代码都是一些属性的设置。 applyConfiguration(factory); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); } if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } if (this.properties.getTypeAliasesSuperType() != null) { factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); } if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); } if (!ObjectUtils.isEmpty(this.typeHandlers)) { factory.setTypeHandlers(this.typeHandlers); } if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { // 设置 mapper.xml 文件的地位。 factory.setMapperLocations(this.properties.resolveMapperLocations()); } Set<String> factoryPropertyNames = Stream .of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName) .collect(Collectors.toSet()); Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver(); if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) { // Need to mybatis-spring 2.0.2+ factory.setScriptingLanguageDrivers(this.languageDrivers); if (defaultLanguageDriver == null && this.languageDrivers.length == 1) { defaultLanguageDriver = this.languageDrivers[0].getClass(); } } if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) { // Need to mybatis-spring 2.0.2+ factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver); } // 要害办法,进入:**7** return factory.getObject(); }
咱们跟进步骤6中的 factory.getObject() 办法会进入到 SqlSessionFactory 的 buildSqlSessionFactory 办法:
**7.** protected SqlSessionFactory buildSqlSessionFactory() throws Exception { final Configuration targetConfiguration; // 后面的操作都是一些属性的设置 XMLConfigBuilder xmlConfigBuilder = null; if (this.configuration != null) { targetConfiguration = this.configuration; if (targetConfiguration.getVariables() == null) { targetConfiguration.setVariables(this.configurationProperties); } else if (this.configurationProperties != null) { targetConfiguration.getVariables().putAll(this.configurationProperties); } } else if (this.configLocation != null) { xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); targetConfiguration = xmlConfigBuilder.getConfiguration(); } else { LOGGER.debug( () -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration"); targetConfiguration = new Configuration(); Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables); } Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory); Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory); Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl); if (hasLength(this.typeAliasesPackage)) { scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream() .filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface()) .filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias); } if (!isEmpty(this.typeAliases)) { Stream.of(this.typeAliases).forEach(typeAlias -> { targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias); LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'"); }); } if (!isEmpty(this.plugins)) { Stream.of(this.plugins).forEach(plugin -> { targetConfiguration.addInterceptor(plugin); LOGGER.debug(() -> "Registered plugin: '" + plugin + "'"); }); } if (hasLength(this.typeHandlersPackage)) { scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass()) .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers())) .forEach(targetConfiguration.getTypeHandlerRegistry()::register); } if (!isEmpty(this.typeHandlers)) { Stream.of(this.typeHandlers).forEach(typeHandler -> { targetConfiguration.getTypeHandlerRegistry().register(typeHandler); LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'"); }); } targetConfiguration.setDefaultEnumTypeHandler(defaultEnumTypeHandler); if (!isEmpty(this.scriptingLanguageDrivers)) { Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> { targetConfiguration.getLanguageRegistry().register(languageDriver); LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'"); }); } Optional.ofNullable(this.defaultScriptingLanguageDriver) .ifPresent(targetConfiguration::setDefaultScriptingLanguage); if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmls try { targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource)); } catch (SQLException e) { throw new NestedIOException("Failed getting a databaseId", e); } } Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache); if (xmlConfigBuilder != null) { try { xmlConfigBuilder.parse(); LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'"); } catch (Exception ex) { throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); } finally { ErrorContext.instance().reset(); } } targetConfiguration.setEnvironment(new Environment(this.environment, this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory, this.dataSource)); if (this.mapperLocations != null) { if (this.mapperLocations.length == 0) { LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found."); } else { // 从这里开始解析 mapper.xml 文件 for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments()); // XMLMapperBuilder 解析,跟进之 **8.** xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); } LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'"); } } } else { LOGGER.debug(() -> "Property 'mapperLocations' was not specified."); } return this.sqlSessionFactoryBuilder.build(targetConfiguration); }
咱们持续跟进 XMLMapperBuilder 的 parse 办法:
**8.** public void parse() { if (!configuration.isResourceLoaded(resource)) { // 从mapper 文件的根节点开始解析(**9.**) configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingCacheRefs(); parsePendingStatements(); }
查看 configurationElement 办法:
**9.** private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute("namespace"); if (namespace == null || namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } // 此处开始依据 xml 的各个节点解析,并将后果存储到 Configuration 对象中,ResultMap节点解析并存储在 resultMaps 中,增删改查的 sql 封装成一个个 MappedStatement 对象中。 builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); parameterMapElement(context.evalNodes("/mapper/parameterMap")); resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);测 } }
到此为止,mybatis 对于配置文件的解析,封装 sql 的工作根本做好了,接下来的工作是如何调用。
当咱们调用咱们写好的 dao 上的业务办法时,最里面的一层是 jdk 的动静代理,接着往里面一层是 mybaits 的 MapperProxy 代理。查看 MapperProxy 的 invoke 办法:
**10.** public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (method.isDefault()) { if (privateLookupInMethod == null) { return invokeDefaultMethodJava8(proxy, method, args); } else { return invokeDefaultMethodJava9(proxy, method, args); } } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // 下面的办法略过,间接看上面的 execute 办法,这里的 MapperMethod 做了一层缓存 final MapperMethod mapperMethod = cachedMapperMethod(method); // 正真执行 sql 。跟进 MapperMethod 的 execute 办法(**11.**) return mapperMethod.execute(sqlSession, args); }
**11.** public Object execute(SqlSession sqlSession, Object[] args) { Object result; // 判断 sql 的类型,增删改查。 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; }
步骤 11 中依据 sql 的类型来判断执行什么流程,以下以 insert 为例:
**12.** public int insert(String statement, Object parameter) { **11.**中的 sqlSession 为 SqlSessionTemplate,这里的 qlSessionProxy 又是一层代理,代理了 DefaultSqlSession 的 update 办法。 return this.sqlSessionProxy.insert(statement, parameter); }
**13.**public int update(String statement, Object parameter) { try { dirty = true; // 从 Configuration 对象中获取 MappedStatement 对象。 MappedStatement ms = configuration.getMappedStatement(statement); // sql 的是 executor。 return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
持续跟进进入到了 SimpleExecutor 的 doUpdate 办法:
**14.** public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); // 连贯数据库创立 prepareStatement,并应用 handler 为 sql 设置参数。 stmt = prepareStatement(handler, ms.getStatementLog()); // 执行封装好的 sql。 return handler.update(stmt); } finally { closeStatement(stmt); } }
在 SimpleExecutor 中,对于增删改的操作执行的是 doUpdate 办法,而查问走的是 doQuery 办法。
**15.** public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); // 这里的 resultHandler 对数据库查问后果做了封装,封装成 resultMap 对应的 java 类型,再看下 handler.query 办法(**16.**) return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
handler.query 会进入到 PreparedStatementHandler 的 query 办法里:
**16.** public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { // preparedStatement 的执行,该逻辑属于 jdbc,不属于 mybatis 的领域。 PreparedStatement ps = (PreparedStatement) statement; ps.execute(); // resultHandler 对查问的后果进行封装成咱们想要的 java 类型。 return resultSetHandler.handleResultSets(ps); }
小结
次要从两个方面讲述了 springboot-mybatis 的基本功能:MapperScan 应用 @Import 在容器中注册了一个 MapperScannerRegistrar,实现了对 basePackages 的接口文件的解析,并替换掉 bean 的类型为 MapperFactoryBean。而 MybatisAutoConfiguration 则创立了 SqlSessionFactory 的 bean,创立过程中实现了对 mapper.xml 文件的解析,并寄存于 SqlSessionFactory 的 Confuguration 属性当中。而在自定义 dao 的 bean 实例化之后,通过属性注入,将 SqlSessionFactory 注入到各个 dao 的 bean 中。在 dao 办法的执行中, jdk 代理的是 MapperProxy,理论通过执行 MapperMethod 办法。sql 语句的执行由 Executor 执行,在获取数据的的 preparedStatment 之后,通过 ParameterHandler 对预编译语句参数设置。ResultHandler 对数据查问后果封装成咱们须要的 java 类型。