springboot整合mybatis以及mybatis源码分析
1、@ComponentScan basePackages与value: 用于指定包的路径,进行扫描 basePackageClasses: 用于指定某个类的包的路径进行扫描 nameGenerator: bean的名称的生成器 useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测 url: https://blog.csdn.net/u012326462/article/details/82765485
2、@ImportResource注解 用于导入 Spring 的 xml 配置文件,让该配置文件中定义的 bean 对象加载到Spring容器中。 参考链接:https://blog.csdn.net/lzb348110175/article/details/105148214
3、 引入依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId> </dependency>
在上述BeanFactory的后置处理器中就会读取mybatis-spring-boot-autoconfigure-***.jar包中的spring.factories文件 /org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.1.0/mybatis-spring-boot-autoconfigure-2.1.0.jar!/META-INF/spring.factories org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
<!-- 通过扫描的模式,扫描目录在mapper目录下,所有的mapper都继承SqlMapper接口的接口, 这样一个bean就可以了-->
@MapperScan和@Mapper都可以,@Mapper每个接口都要写 为什么没有加@MapperScan注解也可以扫描mapper接口 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.hsjry.convert.dal.dao.mapper.**" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean>
扫描调用栈 1.org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.String)
2.org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.String) 声明要注册的对象 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
3. 向这个注册中心注册一个新的 bean 定义 要用到BeanDefinitionRegistry org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition
4.org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry
5.org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
6.org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan @return 注册的 bean set集 Set<BeanDefinitionHolder>
7.org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
8.ClassPathMapperScanner extends ClassPathBeanDefinitionScanner
9.扫描到mapper接口了 org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions
10.ClassPathMapperScanner#processBeanDefinitions // 处理BeanDefinitions // 入参的beanDefinitions是从mapper接口产生的 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 // 是为了创建mapperFactoryBean对象时,给mapperInterface赋值 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // 设置beanClass = mapperFactoryBean.class definition.setBeanClass(this.mapperFactoryBean.getClass()); ....... // 按类型注入,作用是在创建MapperFactoryBean对象时,通过set方法按类型实现装配 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } } }
11.org.mybatis.spring.mapper.MapperFactoryBean#getObject public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> 很多都是在spring做扩展
12.org.apache.ibatis.session.SqlSession#getMapper interface
13.org.mybatis.spring.SqlSessionTemplate#getMapper
14.org.apache.ibatis.session.Configuration#getMapper 这个就是SqlSession接口的方法
15.org.apache.ibatis.binding.MapperRegistry#getMapper
16.org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)
17.org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.binding.MapperProxy<T>),在这个方法中,使用JDK动态代理,创建代理对象,该代理对象就是我们Service层的代码中注入的对象 dao层接口。
二.MyBatis的SqlSession是非线程安全的,那Spring的SqlSessionTemplate是怎么解决的这个问题?
1.org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke
2.org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator):
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
//从事务同步管理器中取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);
//放到事务同步管理器中 registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session); return session; }
MyBatis 方法调用路由到从 Spring 的事务管理器获得的正确 SqlSession 事务同步管理器可以认为是一个ThreadLocal的map,这样同一个线程在使用SqlSessionTemplate多次对数据库操作的时候,取到的是同一个SqlSession;而不同的线程取到的是不同的SqlSession,所以说SqlSessionTemplate是线程安全的。
三 MyBatis怎么跟Spring声明式事务配合完成的数据库事务内的增删改查操作?
1.设置数据库连接的自动提交为false
2.通过这个数据库连接进行sql语句执行
3.异常回滚或者提交 以上三步中的1和3是Spring声明式事务做的,2是MyBatis做的,它们是怎么配合的呢?其实只需要保证1、2、3这三步中获取到的是同一个数据库连接就好,其实也是通过事务同部管理器这个ThreadLocal的map来实现的 1.org.springframework.transaction.interceptor.TransactionInterceptor#invoke>>
TransactionInterceptor extends TransactionAspectSupport
//存在在threadLocal里面去
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 》》
org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#bindToThread
2.org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)
去spring 管理的事务同步管理器中拿sqlSession 拿不到就拿传进来的SqlSessionFactory去开一个session org.apache.ibatis.session.SqlSessionFactory#openSession(org.apache.ibatis.session.ExecutorType) >>> org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(org.apache.ibatis.session.ExecutorType)>>>
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource>>>
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null; try { final Environment environment = configuration.getEnvironment();
//创建的是 就是TransactionFactory实现类org.apache.ibatis.transaction.managed.ManagedTransactionFactory
//从环境配置中拿到的是org.apache.ibatis.transaction.TransactionFactory final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// autoCommit是false
//new org.mybatis.spring.transaction.SpringManagedTransaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
}
catch (Exception e) { closeTransaction(tx);
// may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
}
finally {
ErrorContext.instance().reset();
}
}
3.org.mybatis.spring.transaction.SpringManagedTransaction#getConnection>>
org.mybatis.spring.transaction.SpringManagedTransaction#openConnection>>
org.springframework.jdbc.datasource.DataSourceUtils#getConnection>>
org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
四.springboot整合mybatis是怎么做到不用配置mybatis-config.xml的呢?
1.https://mybatis.org/mybatis-3/configuration.html mybatis-config.xml属性参考官网文档
2.用mybatis-config.xml配置文件 org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.Reader, java.lang.String, java.util.Properties)》》
//解析配置文件得到Configuration对象,得到DefaultSqlSessionFactory对象
org.apache.ibatis.session.SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)》》
org.apache.ibatis.builder.xml.XMLConfigBuilder#parse》》
org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration 这里的顺序有依赖关系 properties先解析 后面environments,databaseIdProvider都可以用到
properties》settings》typeAliases》plugins》objectFactory》objectWrapperFactory》reflectorFactory》environments》databaseIdProvider》typeHandlers》mappers
3.springboot自动配置 引入依赖 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> 要使配置生效两种方式
1、@EnableConfigurationProperties(MybatisProperties.class)org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration @EnableConfigurationProperties 注解的作用是:让使用了 @ConfigurationProperties 注解的类生效,并且将该类注入到 IOC 容器中,交由 IOC 容器进行管理
2、使用 @ConfigurationProperties + @Component 注解 用于自定义默认设置的配置对象。如果指定了 {@link #configLocation},则 * 不使用此属性
@NestedConfigurationProperty private Configuration configuration; 表示 {@link ConfigurationProperties} 对象中的字段应该被视为 * 如果它是嵌套类型。此注释与实际绑定 * 进程无关,但它被 {@code spring-boot-configuration-processor} 用作提示 * 字段未绑定为单个值。指定时,*为该字段创建一个嵌套组,并获取其类型。 * <p> * 这对collections and maps没有影响,因为这些类型是自动识别的 前缀是mybatis加@NestedConfigurationProperty 我们就可以表明它是嵌套组了 可以在配置设置这个对象里面的值
mybatis:
configuration:
cache-enabled:
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
提示应该在其他指定的自动配置类之后应用 {@link EnableAutoConfiguration 自动配置} 这个注解表示DataSourceAutoConfiguration MybatisLanguageDriverAutoConfiguration要在MybatisAutoConfiguration 后执行 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration》》
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties 前缀是spring.datasource 动态代理
spring整合mybatis的debug的步骤:
org.apache.ibatis.session.defaults.DefaultSqlSession@14d6f58f
org.apache.ibatis.session.SqlSession#insert(java.lang.String, java.lang.Object)
org.apache.ibatis.binding.MapperProxy#invoke》》
org.apache.ibatis.binding.MapperMethod#execute》》
org.mybatis.spring.SqlSessionTemplate#insert(java.lang.String, java.lang.Object)》》
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke》》
org.apache.ibatis.session.defaults.DefaultSqlSession#insert(java.lang.String, java.lang.Object)》》也是通过代理生成的,传统的操作是直接工厂模式new
org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object)》》
org.apache.ibatis.plugin.Plugin#invoke》》
org.apache.ibatis.executor.CachingExecutor#update》》这里面不用创建缓存只有query才需要
org.apache.ibatis.executor.BaseExecutor#update》》
org.apache.ibatis.executor.BaseExecutor#doUpdate》》
org.apache.ibatis.executor.SimpleExecutor#doUpdate》》
org.apache.ibatis.executor.statement.SimpleStatementHandler#update》》
java.sql.Statement#execute(java.lang.String)
jdbc里内容了
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
Plugin里的invoke方法
一堆代理
springboot整合mybatis以及mybatis源码分析的更多相关文章
- Springboot中mybatis执行逻辑源码分析
Springboot中mybatis执行逻辑源码分析 在上一篇springboot整合mybatis源码分析已经讲了我们的Mapper接口,userMapper是通过MapperProxy实现的一个动 ...
- MyBatis 之 SqlSessionManager 源码分析
MyBatis 的 4 个基本构成: SqlSessionFactoryBuilder(构造器): 根据配置信息或者代码来生成 SqlSessionFactory(工厂接口) SqlSessionFa ...
- MyBatis架构与源码分析<资料收集>
1.架构与源码分析 :https://www.cnblogs.com/luoxn28/p/6417892.html .https://www.cnblogs.com/wangdaijun/p/5296 ...
- springboot Properties加载顺序源码分析
关于properties: 在spring框架中properties为Environment对象重要组成部分, springboot有如下几种种方式注入(优先级从高到低): 1.命令行 java -j ...
- SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)
SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...
- SpringBoot与Mybatis整合方式01(源码分析)
前言:入职新公司,SpringBoot和Mybatis都被封装了一次,光用而不知道原理实在受不了,于是开始恶补源码,由于刚开始比较浅,存属娱乐,大神勿喷. 就如网上的流传的SpringBoot与Myb ...
- Mybatis原理及源码分析
什么是Mybatis? Mybatis是一个半自动化的持久层框架. Mybatis可以将向PreparedStatement中的输入参数自动进行映射(输入映射),将结果集映射成Java对象(输出映射) ...
- mybatis 学习四 源码分析 mybatis如何执行的一条sql
总体三部分,创建sessionfactory,创建session,执行sql获取结果 1,创建sessionfactory 这里其实主要做的事情就是将xml的所有配置信息转换成一个Confi ...
- 学习SpringBoot整合SSM三大框架源码之SpringBoot
Spring Boot源码剖析 一.Spring Boot 项目的启动入口流程分析 Spring Boot项目的启动入口main线程上有一个@SpringBootApplication( @Confi ...
- SpringBoot @ConditionalOnBean、@ConditionalOnMissingBean注解源码分析与示例
前言: Spring4推出了@Conditional注解,方便程序根据当前环境或者容器情况来动态注入bean,对@Conditional注解不熟悉的朋友可移步至 Spring @Conditional ...
随机推荐
- metasploit2-practice
Metasploittable2打靶教程 本次靶机练习主要熟悉:高危端口利用:metasploit中search,show及各个模块使用. 一.环境准备 1.把靶场放在vmware打开,启用nat模式 ...
- wordpress配置指南
1.创建资源 在页面左侧,单击 云产品资源 下拉列表,查看本次实验所需资源. 单击屏幕右侧 创建资源 ,免费创建当前实验所需云产品资源. 资源创建过程需要1~3分钟.完成实验资源的创建后,您可以在 云 ...
- 个人博客系统Typecho情侣主题模板Cupid
个人博客系统Typecho情侣主题模板Cupid 转载:https://zcjun.com/3175.html
- K3S系列文章-使用AutoK3s在腾讯云上安装高可用K3S集群
开篇 <K3s 系列文章> <Rancher 系列文章> 方案 在腾讯云上安装 K3S 后续会在这套 K3S 集群上安装 Rancher 方案目标 高可用 3 台master ...
- SnakeYaml的不出网反序列化利用分析
SnakeYaml的常见出网利用方式: !!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ...
- 首个比较研究表明维持期强柱患者减量续用TNFi疗效尚佳且药费省
首个比较研究表明维持期强柱患者减量续用TNFi疗效尚佳且药费省 Zavada J, et al. Ann Rheum Dis. 2016,75: 96-102. 电邮发布日期: 2016年5月4日 关 ...
- KB 与 KiB
字节(Byte)是计算机中存储数据的基本单位,每 8 位比特(bit)组成一个字节.各种信息在计算机中存储.处理至少需要一个字节.例如,一个 ASCII 码用一个字节表示,一个汉字用两个字节表示. 根 ...
- AI绘画--tag资源
tag生成器:https://wolfchen.top/tag/ 资源整合表:https://wolfchen.top/tag/doc.html 魔咒百科词典:https://aitag.top/ N ...
- C++基础复习题(笔试题)
C++基础~for循环:选择,判断 HELLO,亲爱的小朋友! 我们准备 35个选择题,对for循环及之前的内容进行一个简单的复习,快来看一下吧! 顺序&选择结构 1.对于C++中变量的命名规 ...
- windows 10中Microsoft Edge Beta登录账户提示:以管理员身份运行 Microsoft Edge 时不支持登录。请以非管理员身份重新启动 Microsoft Edge,然后重新尝试登录。的解决方案
windows 10中Microsoft Edge Beta登录账户提示:以管理员身份运行 Microsoft Edge 时不支持登录.请以非管理员身份重新启动 Microsoft Edge,然后重新 ...