【Mybatis源码解析】-mybatis-spring原理解析
2021-03-20 21:25
标签:tcl intercept 容器 直接 mapper repeat target context sources ? 没有spring使用Mybatis的步骤是 1:创建SqlSessionFactoryBuilder 2: 通过SqlSessionFactoryBuilder创建要给SqlSessionFactory 3: 创建SqlSession 4: 获取Mapper的代理对象 5:执行获取结果 很多都是重复步骤,可以交给spring去管理 ? Mybatis-spring主要做的内容包含: 我们从使用过程到执行过程分步讲解原理。 入口: 使用Mybatis-spring,需要主动配置SqlSessionFactoryBean,所以配置初始化的流程从这里开始。 SqlSessionFactoryBean实现了 FactoryBean,用于自定义Bean实例化逻辑,并注册到Spring容器。SqlSessionFactory是一个很重的类,实例的化的过程比较复杂繁琐。 ApplicationListener,监听的是ContextRefreshedEvent事件,配置了快速失败时检查MapperedStatement是否加载完毕。 InitializingBean,真正开始实例化的时机,开始构建SqlSessionFactory。 构造过程:也就是解析配置文件,构造Configuration过程 mapper扫描路径配置常见有两种方式 因为MapperScan注解最终也是生成MapperScannerConfigurer类的实例,其使用也更方便,那么就从MapperScan开始介绍。 过程概览: ? 主要作用就是:主要作用就是提供可配置路径,导入MapperScannerRegistrar。比较简单。 ? MapperScannerRegistrar就是一个mapper扫描注册器,用于读取注解上的值并注册一个Mapper扫描配置类。 借助Spring的import机制,构造并注册MapperScannerConfigurerBeanDefinition 主要点就在于构造扫描器。扫描Mapper的BeanDefinition并注册。 继承Spring的扫描工具类,覆盖doScan完成自定义部分。 这里有两个点: MapperFactoryBean负责Mapper实例的创建,来看看MapperFactoryBean这个类。 类图如下: 获取Mapper实例的逻辑和单独使用Mapper的时候相同,获取SqlSession,使用SqlSession为mapper创建代理对象。 getSqlSession()方法在父类SqlSessionDaoSupport中。 ? SqlSessionTemplate属性就是在MapperFactoryBean实例化的时候自动注入进去的,我们看一看SqlSessionTemplate。实现了SqlSession,可以代表成一个SqlSession,主要还是为了管理SqlSession的代理类。 来看下SqlSessionTemplate的构造方法。 sqlSessionProxy是真正的SqlSession代理类,SqlSession相关方法的实现,SqlSessionTemplate都是委托给SqlSessionProxy实现的。 重点在于SqlSession代理类,这个类使用了JDK的动态代理,来看看究竟拦截方法并做了什么。 让我们看看SqlSessionInterceptor SqlSessionInterceptor是SqlSessionTemplate的内部类,实现了InvocationHandler(JDK动态代理必备)。 SqlSessionTemplate伪装成SqlSession,实现其接口,内部实现委托给SqlSessionProxy完成。 事务控制着Connection,与Connection对应的则是SqlSession。看看mybatis-spring怎么对接的Spring事务去控制SqlSession。 在上面SqlSessionInterceptor的invoke部分,获取SqlSession,调用的是 继续看下内部如何实现 这里简单的提一点Spring事务,Spring会使用ThreadLocal保存事务的信息,在这里mybatis=spring借助TransactionSynchronizationManager.getResource/bindResource来获取/绑定SqlSession。 到这里可以看到,通过对接TransactionSynchronizationManager,实现了与Spring事务的对接。 通过ThreadLocal存储了一个HashMap,key是SqlSessionFactory,value是SqlSession,代表一个线程在一个事务中一个数据源只能有一个Connection,事务中不能切换Connection,所以SqlSession将会被复用。 mybatis-spring事务总结一下: 对接事务就是通过对接Spring事务来管理SqlSession的创建/获取/销毁, 事务开启时获取SqlSession实例时使用TransactionSynchronizationManager获取,一个线程一个map,key是SqlSessionFactory,value是SqlSession。 事务关闭、提交时,也是先删除资源,再调用sqlSession的close方法,完成资源关闭。 【Mybatis源码解析】-mybatis-spring原理解析 标签:tcl intercept 容器 直接 mapper repeat target context sources 原文地址:https://www.cnblogs.com/simple-flw/p/13909479.htmlmybatis-spring原理解析
mybatis-spring
就是帮助处理这些工作,
1、初始化过程
SqlSessionFactoryBean
FactoryBean
,InitializingBean
,ApplicationListener
1.1、SqlSessionFactory初始化
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property ‘dataSource‘ is required");
notNull(sqlSessionFactoryBuilder, "Property ‘sqlSessionFactoryBuilder‘ is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property ‘configuration‘ and ‘configLocation‘ can not specified with together");
// 开始构造
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final Configuration targetConfiguration;
XMLConfigBuilder xmlConfigBuilder = null;
// 指定了mybatis-config.xml的路径时
else if (this.configLocation != null) {
// 构造xml解析器
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
}
// 啥都没指定,直接实例化Configuration,使用默认配置
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 + "‘");
});
}
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);
// 执行了Config路径时需要解析
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));
// mapper.xml文件地址
if (this.mapperLocations != null) {
if (this.mapperLocations.length == 0) {
LOGGER.warn(() -> "Property ‘mapperLocations‘ was specified but matching resources are not found.");
} else {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
// 遍历解析xml并注册
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
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.");
}
// 将设置好的Configuration交由SqlSessionFactoryBuilder进行构造
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
SqlSessionFactory就已经初始化完毕了,SqlSessionFactory的实例单例保存在Spring容器中,具体在Mybatis的哪个类中自动使用,稍后再说。
1.2 Mapper扫描、注册
1.2.1 MapperScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//导入Bean,
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan
1.2.2 MapperScannerRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
// mapperScanner注解属性构造,构造MapperScannerConfigurer的BeanDefinition
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
1.2.3 MapperScannerConfigurer
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 占位符替换
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
// 构造扫描器进行扫描包,批量构造mapper
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.registerFilters();
// 执行扫描注册
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
1.2.4 ClassPathMapperScanner
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner
@Override
public Set
private void processBeanDefinitions(Set
执行过程
public class MapperFactoryBean
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
@SuppressWarnings("WeakerAccess")
protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;
}
}
2.2 SqlSession实例创建
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
// SqlSession代理类
private final SqlSession sqlSessionProxy;
// 异常翻译器,将mybatis的异常转换成Spring的异常
private final PersistenceExceptionTranslator exceptionTranslator;
}
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property ‘sqlSessionFactory‘ is required");
notNull(executorType, "Property ‘executorType‘ is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
// 创建SqlSession代理类实例
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取真正的SqlSession实例
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
// 执行SqlSession的方法(举例:sqlSession.getMapper(XXX.class))
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// 如果SqlSession未处于spring事务,那设置未自动提交
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) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
2.3 事务
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
// 从spring 事务中获取SqlSession
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);
// 将SqlSession注册到 spring事务中
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
// 判断当前同步是否激活
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
// 如果是SpringManagedTransactionFactory则进行spring事务对接
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
LOGGER.debug(() -> "Registering transaction synchronization for SqlSession [" + session + "]");
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
// 绑定SqlSession信息到当前线程中,key是SqlSessionFactory
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
TransactionSynchronizationManager
.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because DataSource is not transactional");
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because synchronization is not active");
}
}
文章标题:【Mybatis源码解析】-mybatis-spring原理解析
文章链接:http://soscw.com/index.php/essay/66874.html