pom引入依赖
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
springboot启动配置bean
@Configuration
@ImportResource(locations = { "classpath:spring/*" })
@PropertySource("classpath:config/datasource.properties")
@ComponentScan(basePackages = "org.gallant.spring")
@MapperScan("org.gallant.spring.transaction.mapper")
@EnableTransactionManagement
public class AppContext {
}
mybatis为了整合springboot开发了starter桥接包与实现包。桥接包中指定自动配置的实现提供者:provides: mybatis-spring-boot-autoconfigure,mybatis,mybatis-spring。查看mybatis自动配置类实现源码如下
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
...//暂时仅关注注解部分
}
EnableConfigurationProperties注解指定EnableConfigurationPropertiesImportSelector导入选择器导入ConfigurationPropertiesBeanRegistrar配置bean定义并注册至上下文、ConfigurationPropertiesBindingPostProcessorRegistrar将ConfigurationPropertiesBindingPostProcessor注册至上下文,ConfigurationPropertiesBindingPostProcessor将在配置bean初始化前绑定配置属性postProcessBeforeInitialization。配置bean类型为MybatisProperties,名称为mybatis-org.mybatis.spring.boot.autoconfigure.MybatisProperties(如果有前缀),配置MybatisProperties类的ConfigurationProperties注解指定配置的前缀为mybatis。
创建SqlSessionFactoryBean,根据properties配置factory,获取SqlSessionFactory bean
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
...
// 1.根据配置初始化Configuration
// 1.x 根据mapperLocations解析mapper xml文件至configuration.getSqlFragments
// 2. 根据Configuration配置构建SqlSessionFactory实例
// return this.sqlSessionFactoryBuilder.build(configuration);
this.sqlSessionFactory = buildSqlSessionFactory();
}
Mapper扫描
// class : MybatisAutoConfiguration 的内部类
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
logger.debug("Searching for mappers annotated with @Mapper");
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
try {
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
for (String pkg : packages) {
logger.debug("Using auto-configuration base package '{}'", pkg);
}
}
scanner.setAnnotationClass(Mapper.class);
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(packages));
} catch (IllegalStateException ex) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
MapperScan注解指定导入MapperScannerRegistrar。import注解在spring上下文刷新时导入指定的bean。具体逻辑可以查看ConfigurationClassParser.processImports方法。
MapperScannerRegistrar源码分析
AbstractApplicationContext.finishBeanFactoryInitialization执行上下文中非懒惰加载bean的初始化
ConstructorResolver.autowireConstructor构造Mapper实例,Mapper bean定义类型为org.mybatis.spring.mapper.MapperFactoryBean,候选的构造器列表如下
按照选中的构造器(有class为入参的构造器),使用CglibSubclassingInstantiationStrategy父类SimpleInstantiationStrategy.instantiate创建动态代理对象,如果getMethodOverrides为空则调用BeanUtils._instantiateClass,否则调用子类重写的_instantiateWithMethodInjection方法
MapperFactoryBean实现了spring的FactoryBean接口,通过spring容器回调(AbstractBeanFactory.getObjectForBeanInstance)getObject构建Mapper返回
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
SqlSessionTemplate会话模板获取Mapper
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
Configuration配置获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry注册中心获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从已知Mapper类型缓存中获取代理工厂,此处是一个map,key为mapper类型,value为代理工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
// mapper代理工厂创建mapper实例
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
Mapper代理工厂创建Mapper实例,可以看到使用的是jdk自带的动态代理
// 类:MapperProxyFactory
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<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
// 根据配置文件、接口、方法创建Mapper方法命令
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
MapperMethod实例
// 类:MapperMethod
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
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;
}
...
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;
}
// MapperMethod的内部类SqlCommand
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
// 根据配置文件解析Mapped语句
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
...
}
// MapperMethod的内部类SqlCommand
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
String statementId = mapperInterface.getName() + "." + methodName;
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
// 递归调用实现的父接口
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
...
}
}
return null;
}