Spring Framework集成之Mybatis

一、前言

mybatis作为ORM(Object Relational Mapping)首选框架,融入Spring Framework大家族自然是必要的,话不多说。通过下面3点我们将了解简单的Mybatis-Spring:

主要是做集成,了解其扫描运行机制,不会去往深处进行数据库查询

1.Mybatis-Spring的简单使用
2.游走Mybatis-Spring集成机制源码
3.游走Mybatis-Spring集成机制源码 - 番外篇(特殊的sqlSession)

二、Mybatis-Spring的简单使用

准备
类结构图
avatar
类包依赖
gradle

1
2
3
4
5
6
7
8
9
// ==================== spring framework ====================
testImplementation 'org.springframework:spring-context:5.3.5'
// ==================== mybatis ====================
testImplementation 'org.mybatis:mybatis:3.5.7'
testImplementation 'org.mybatis:mybatis-spring:2.0.6'
// ==================== spring tx ====================
testImplementation 'org.springframework:spring-tx:5.3.5'
// ==================== spring jdbc ====================
testImplementation 'org.springframework:spring-jdbc:5.3.5'

maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>

类结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package mybatis.bean;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Mapper
public interface MybatisBean {
@Select("select * from user")
List<Object> queryAll();
}
-------------------------------------------------------------
package mybatis.config;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
* mybatis配置类
*/
@Component
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory(), ExecutorType.REUSE);
}

public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(new PooledDataSource());//mybatis的数据源池
return factoryBean.getObject();
}
}
-------------------------------------------------------------
package mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@Component
@ComponentScan
@MapperScan
public class MybatisScanner {

}

junit代码块

1
2
3
4
5
6
7
8
9
10
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MybatisScanner.class);
// 刷新应用上下文
context.refresh();
Arrays.asList(context.getBeanDefinitionNames())
.forEach(System.out::println);
}

执行输出结果

1
2
3
4
5
6
7
8
9
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mybatisScanner
myBatisConfig
sqlSession
mybatis.MybatisScanner#MapperScannerRegistrar#0
mybatisBean

三、游走Mybatis-Spring集成机制源码

由于Mybatis-Spring是可插拔的数据库资源代理使用,所以需要手动注明,注解使用为@MapperScan和@MapperScans两种

@MapperScan
avatar

通过@Import会将MapperScannerRegistrar.class注入到Spring Framework中,这边直接看处理

MapperScannerRegistrar
avatar
avatar
MapperScannerConfigurer

类结构图

avatar

在获取Bean的时候,在initializeBean中回调ApplicationContextAware接口的setApplicationContext方法、BeanNameAware接口的setBeanName方法、InitializingBean接口的afterPropertiesSet方法(具体看Spring Framework的Bean生成)

avatar
avatar
avatar
Mybatis实现了自己的扫描器,作用域在refresh的invokeBeanFactoryPostProcessors方法中
avatar

ClassPathMapperScanner继承自ClassPathBeanDefinitionScanner,对其doScan进行了重写,使用父类的scan

ClassPathBeanDefinitionScanner
avatar
ClassPathMapperScanner
avatar

调用父类的doScan会触发findCandidateComponents方法,进行组件的查找和验证,Mybatis-Spring重写了组件的验证逻辑

avatar
avatar

四、游走Mybatis-Spring集成机制源码 - 番外篇(特殊的sqlSession)

总体释义:获取一个mybatis的接口bean,会使用sqlSessionTemplate代理的方式进行处理

代码块

1
context.getBean(MybatisBean.class);

由于Spring Framework对bean回去已做了充分说明,这边直接通过流程图进行说明

运行时流程图
avatar
MapperFactoryBean
avatar
SqlSessionTemplate
avatar
Configuration

此处就是调用mybatis的Configuration获取mapper的动态代理逻辑了,想获取更多看Mybatis的代理篇

avatar
通过获取bean使用
SqlSessionTemplate

构造生成的代理尤为重要,最终会走向SqlSessionInterceptor

avatar

Mybatis-Spring使用sqlSessionTemplate进行处理

avatar
SqlSessionInterceptor

最终走向,会通过事物同步管理器来复用session(复用有一定的条件),此时的sqlSession就是mybatis篇我们熟悉的DefaultSqlSession

avatar
avatar

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信