1.Mybatis解析配置部分
下圖是解析配置類的UML圖

SqlSessionFactoryBuilder
1 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { 2 try { 3 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); 4 return build(parser.parse()); 5 } catch (Exception e) { 6 throw ExceptionFactory.wrapException("Error building SqlSession.", e); 7 } finally { 8 ErrorContext.instance().reset(); 9 try { 10 inputStream.close(); 11 } catch (IOException e) { 12 // Intentionally ignore. Prefer previous error. 13 } 14 } 15 } 16 17 public SqlSessionFactory build(Configuration config) { 18 return new DefaultSqlSessionFactory(config); 19 }
XMLConfigBuilder負責解析配置文件,XMLConfigBuilder會調用XPathParser 產生Configuration對象,XPathParser 利用XPath技術解析XML,Configuration里面存儲的都是config配置文件各種信息,我們也可以編程自己實例化Configuration來創建SqlSessionFactory
還有類MapperAnnotationBuilder是用來解析注解配置Mapper
類XMLMapperBuilder是用來解析Xml配置Mapper
2.Spring整合Mybatis
SqlSessionFactoryBean
MapperFactoryBean
SqlSessionFactoryBean
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
Spring整合Mybatis最重要的是上面兩個FactoryBean,FactoryBean是Spring一種特殊的Bean,Spring會調用getObject方法產生Bean
現在簡單看下SqlSessionFactoryBean 源碼,看源碼最后會調用到方法buildSqlSessionFactory,在下面源碼我們看到了熟悉的幾個類XMLConfigBuilder、Configuration、SqlSessionFactoryBuilder、SqlSessionFactory、XMLMapperBuilder(解析Xml的Mapper,注解的Mapper是MapperFactoryBean)
1 protected SqlSessionFactory buildSqlSessionFactory() throws IOException { 2 3 Configuration configuration; 4 5 XMLConfigBuilder xmlConfigBuilder = null; 6 if (this.configuration != null) { 7 configuration = this.configuration; 8 if (configuration.getVariables() == null) { 9 configuration.setVariables(this.configurationProperties); 10 } else if (this.configurationProperties != null) { 11 configuration.getVariables().putAll(this.configurationProperties); 12 } 13 //如果配置了configLocation,則直接調用XMLConfigBuilder得到Configuration 14 } else if (this.configLocation != null) { 15 xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); 16 configuration = xmlConfigBuilder.getConfiguration(); 17 } else { 18 //如果沒有配置configLocation,先直接new Configuration 19 if (LOGGER.isDebugEnabled()) { 20 LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration"); 21 } 22 configuration = new Configuration(); 23 if (this.configurationProperties != null) { 24 configuration.setVariables(this.configurationProperties); 25 } 26 } 27 //配置前面得到的Configuration,Configuration的set設置都是FactoryBean的配置屬性 28 //……. objectFactory 29 30 //……objectWrapperFactory 31 32 //………. vfs 33 34 //………typeAliasesPackage 35 36 //……….. typeAliases 37 38 //……………plugins 39 40 //…………typeHandlersPackage 41 42 //…………typeHandlers 43 44 //…………. databaseIdProvider 45 46 //……………….cache 47 48 //配置了configLocation的時候解析 49 if (xmlConfigBuilder != null) { 50 try { 51 xmlConfigBuilder.parse(); 52 53 if (LOGGER.isDebugEnabled()) { 54 LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'"); 55 } 56 } catch (Exception ex) { 57 throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); 58 } finally { 59 ErrorContext.instance().reset(); 60 } 61 } 62 //沒有配置transactionFactory 默認指定SpringManagedTransactionFactory 63 if (this.transactionFactory == null) { 64 this.transactionFactory = new SpringManagedTransactionFactory(); 65 } 66 67 configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource)); 68 69 if (!isEmpty(this.mapperLocations)) { 70 for (Resource mapperLocation : this.mapperLocations) { 71 if (mapperLocation == null) { 72 continue; 73 } 74 //解析XmlMapper,如果配置了mapperLocations 75 try { 76 XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), 77 configuration, mapperLocation.toString(), configuration.getSqlFragments()); 78 xmlMapperBuilder.parse(); 79 } catch (Exception e) { 80 throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); 81 } finally { 82 ErrorContext.instance().reset(); 83 } 84 85 if (LOGGER.isDebugEnabled()) { 86 LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'"); 87 } 88 } 89 } else { 90 if (LOGGER.isDebugEnabled()) { 91 LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found"); 92 } 93 } 94 95 return this.sqlSessionFactoryBuilder.build(configuration); 96 }
MapperFactoryBean
1 <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> 2 <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" /> 3 <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 4 </bean>
這個是處理注解的Mapper,簡單的看下他的getObject方法,先看下這個類的簽名,在看它的getObject方法
public class MapperFactoryBean<T> extends SqlSessionDaoSupport
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
這個是注解Mapper的正常用法。
MapperScannerConfigurer類
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>
這個這個類會更具指定的basePackage來自動裝配MapperFactoryBean,但如果指定了多個DataSource,則必須指定 sqlSessionFactoryBeanName屬性
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
SqlSessionTemplate
SqlSessionDaoSupport
上面兩個類是Spring對於Mybatis DAO支持的具體實現類
3.SpringBoot整合Mybatis
用mybatis-spring-boot-starter來進行pom更新來支持mybatis starter開發,分析Spring Boot知道,AutoConfiguration是starter的核心,boot加載的時候會讀取classpath下的spring.factories,下面是Mybatis的AutoConfiguration配置
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
可以看到類org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
現在看下這個類的簽名
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
publicclass MybatisAutoConfiguration {……..}
Configuration注解:說明這是spring的配置項,容器初始化的時候要進行解析處理
ConditionalOnClass注解:有類SqlSessionFactory(Mybatis),SqlSessionFactoryBean(Mybatis-Spring)的時候才進行解析處理
ConditionalOnBean:容器中有DataSource Bean的時候才進行解析處理
AutoConfigureAfter注解: 在DataSourceAutoConfiguration后解析
EnableConfigurationProperties注解和MybatisProperties類:配置自己的Mybatis 屬性,在Application.Properties中。
看MybatisAutoConfiguration源碼,幾點
1. SqlSessionFactory
@Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource){…………….} 實例化SqlSessionFactory bean
2. sqlSessionTemplate
@Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){………………}
3. MapperScannerRegistrarNotFoundConfiguration
1 @org.springframework.context.annotation.Configuration 2 @Import({ AutoConfiguredMapperScannerRegistrar.class }) 3 @ConditionalOnMissingBean(MapperFactoryBean.class) 4 public static class MapperScannerRegistrarNotFoundConfiguration { 5 6 @PostConstruct 7 public void afterPropertiesSet() { 8 logger.debug("No {} found.", MapperFactoryBean.class.getName()); 9 } 10 }
如果沒有使用MapperScann這個注解,會自動去搜索Mapper,看下源碼,Import注解里面的類才是關鍵AutoConfiguredMapperScannerRegistrar,看他的registerBeanDefinitions方法源碼,發現它會去類路徑下去搜索Mapper注解的類生成MapperFactoryBean
1 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 2 3 logger.debug("Searching for mappers annotated with @Mapper"); 4 5 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); 6 7 try { 8 if (this.resourceLoader != null) { 9 scanner.setResourceLoader(this.resourceLoader); 10 } 11 12 List<String> packages = AutoConfigurationPackages.get(this.beanFactory); 13 if (logger.isDebugEnabled()) { 14 for (String pkg : packages) { 15 logger.debug("Using auto-configuration base package '{}'", pkg); 16 } 17 } 18 19 scanner.setAnnotationClass(Mapper.class); 20 scanner.registerFilters(); 21 scanner.doScan(StringUtils.toStringArray(packages)); 22 } catch (IllegalStateException ex) { 23 logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex); 24 } 25 }
最后看下MapperScann注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {}
看類MapperScannerRegistrar的registerBeanDefinitions方法,最后也是借用ClassPathMapperScanner類去掃描Mapper注解
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
returnnew DefaultSqlSessionFactory(config);
}
