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);
}