1. xml 集成原理
1.1 xml 配置
<!-- 自动的扫描所有的 mapper 的实现并加入到 ioc 容器中 -->
<bean id="configure" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--basePackage:指定包下所有的 mapper 接口实现自动扫描并加入到 ioc 容器中-->
<property name="basePackage" value="pers.mangseng.study.mybatis.mapper"/>
</bean>
1.2 xml 原理
1.2.1 MapperScannerConfigurer#postProcessBeanDefinitionRegistry
- org.mybatis.spring.mapper.MapperScannerConfigurer
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
- 由于实现了
BeanDefinitionRegistryPostProcessor
接口,所以重点关注postProcessBeanDefinitionRegistry
方法
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
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.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
2. 注解集成原理
2.1 注解配置
@Configuration
// 配置 mybatis 扫描注解包
@MapperScan(basePackages = "pers.mangseng.study.mybatis.mapper")
@EnableTransactionManagement(proxyTargetClass = true)
public class MybatisConfig {
2.2 注解原理
2.2.1 MapperScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 给容器中导入 MapperScannerRegistrar 组件 ------> 2.2.2
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
2.2.2 MapperScannerRegistrar#registerBeanDefinitions
- org.mybatis.spring.annotation.MapperScannerRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取 @MapperScan 的注解信息
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
...
List<String> basePackages = new ArrayList<String>();
// 解析 value 属性,因为 value 同 basePackages,添加到 basePackages 中
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 解析 basePackages 属性,添加到 basePackages 中
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 解析 basePackageClasses 属性,添加到 basePackages 中
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
// 扫包 ------> 2.2.3
scanner.doScan(StringUtils.toStringArray(basePackages));
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
// 注入 resourceLoader
this.resourceLoader = resourceLoader;
}
}
-
由于实现了
ImportBeanDefinitionRegistrar
接口,所以重点关注registerBeanDefinitions
方法refresh() invokeBeanFactoryPostProcessors(beanFactory) PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()) invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry) postProcessor.postProcessBeanDefinitionRegistry(registry) processConfigBeanDefinitions(registry) this.reader.loadBeanDefinitions(configClasses) loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator) loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()) registrar.registerBeanDefinitions(metadata, this.registry)
2.2.3 ClassPathMapperScanner#doScan
- org.mybatis.spring.mapper.ClassPathMapperScanner
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 调用 spring 进行扫包 ------> 2.2.4
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 {
// 调用 processBeanDefinitions 方法给 bean 添加 MyBatis 的功能,否则只是普通的 spring bean ------> 2.2.5
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
2.2.4 ClassPathBeanDefinitionScanner#doScan
- org.springframework.context.annotation.ClassPathBeanDefinitionScanner
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 组装 BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 添加到 beanDefinitions 后返回
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
2.2.5 ClassPathMapperScanner#processBeanDefinitions
- org.mybatis.spring.mapper.ClassPathMapperScanner
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
...
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
// 设置 bean 的 class 类型,为 MapperFactoryBean
definition.setBeanClass(this.mapperFactoryBean.getClass());
...
}
}
2.3 事务原理
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
// 调用 getBean 获取对象 ------> 2.3.1
EmployeeMapper employeeMapper = context.getBean(EmployeeMapper.class);
System.out.println(employeeMapper);
// 调用查询 ------> 2.3.4
Employee employee = employeeMapper.getEmpById(1);
System.out.println(employee);
}
2.3.1 AbstractApplicationContext
- org.springframework.context.support.AbstractApplicationContext#getBean
context.getBean(EmployeeMapper.class)
getBean(requiredType)
getBean(requiredType, (Object[]) null)
resolveBean(ResolvableType.forRawClass(requiredType), args, false)
resolveNamedBean(requiredType, args, nonUniqueAsNull)
new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args))
doGetBean(name, requiredType, args, false)
getObjectForBeanInstance(sharedInstance, name, beanName, null)
super.getObjectForBeanInstance(beanInstance, name, beanName, mbd)
getObjectFromFactoryBean(factory, beanName, !synthetic)
doGetObjectFromFactoryBean(factory, beanName)
// factory 是 MapperFactoryBean ------> 2.3.2
factory.getObject()
2.3.2 MapperFactoryBean
- org.mybatis.spring.mapper.MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public MapperFactoryBean() {
//intentionally empty
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
...
@Override
public T getObject() throws Exception {
// 返回 mapper 的代理对象
// getSqlSession 实际获取到的是 sqlSessionTemplate ------> 2.3.3
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<T> getObjectType() {
// 返回 classType
return this.mapperInterface;
}
@Override
public boolean isSingleton() {
// 单例
return true;
}
....
}
2.3.3 SqlSessionDaoSupport#getSqlSession
-
org.mybatis.spring.support.SqlSessionDaoSupport
-
spring 在调用
populateBean
方法给 bean 赋值时候,会通过反射调用 set 方法,因此会调用setSqlSessionFactory
和setSqlSessionTemplate
方法
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
// 给 sqlSession 赋值,sqlSessionTemplate 是 sqlSession 的实现类
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
// 给 sqlSession 赋值,sqlSessionTemplate 是 sqlSession 的实现类
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
public SqlSession getSqlSession() {
// 返回 sqlSessionTemplate
return this.sqlSession;
}
...
}
2.3.4 MapperMethod#execute
- org.apache.ibatis.binding.MapperMethod
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;
}
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);
// 调用查询方法,注意此时的 sqlSession 是 sqlSessionTemplate ------> 2.3.5
result = sqlSession.selectOne(command.getName(), param);
}
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;
}
2.3.5 SqlSessionTemplate#selectOne
- org.mybatis.spring.SqlSessionTemplate
@Override
public <T> T selectOne(String statement, Object parameter) {
// 重载 ------> 2.3.6
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
}
2.3.6 SqlSessionInterceptor#invoke
- org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 每次都会获取一个新的 sqlSession
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
// 如果没有被 transactional 管理,如果被 aop 代理,则通过 spring 的事务支持来控制
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// 强制提交
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
// 关闭 sqlSession ------> 2.3.7
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
2.3.7 SqlSessionUtils#closeSqlSession
- org.mybatis.spring.SqlSessionUtils
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
// 获取当前 holder 对象
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if ((holder != null) && (holder.getSqlSession() == session)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
}
// 如果 holer 不为 null,调用 released() 方法 ------> 2.3.8
holder.released();
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
}
session.close();
}
}
2.3.8 ResourceHolderSupport#released
- org.springframework.transaction.support.ResourceHolderSupport
public void released() {
// 持有的引用 -1,并没有去关闭 session
this.referenceCount--;
}