纯mybatis获取mapper对象:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = neSqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper session.getMapper(UserMapper.class);
mapper.selectAll();
Springboot集成mybatis 获取mapper对象:
- 准备工作
- application.properties 配置一个数据源
- pom引入mybatis的springboot启动器
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifctId>
<version>2.1.3</version>
</dependency>
- 启动类上使用@MapperScan注解扫描mapper接口
使用:直接到需要使用的bean里面即可
@Autowired
private UserMapper userMapper;
那么问题来了,springboot中,mybatis的mapper接口是如何生成代理对象,并注册到spring ioc容器中的
源码解析
mybatis-spring-boot-starter启动器的作用
引入了以下包
其中自动装配的包就是mybatis-spring-boot-autoconfigure。
mybatis-spring-boot-autoconfigure包
META-INF下有一个spring.factories文件
导入了这个类MybatisAutoConfiguration
根据springboot的spi机制,他会主动去扫描META-INF下的spring.factories中配置的EnableAutoConfiguration的子类,并将其自动装配到spring容器中,这个类的工作就是mybatis集成spring的起源了。
MybatisAutoConfiguration 解析
1.用@Bean的方式SqlSessionFactory,并且将我们自行创建的druid数据源作为参数传了进来
2.用@Bean的方式创建SqlSessionTemplate,讲将上一步注册到spring容器中的SqlSessionFactory作为参数传递进来。
那么是如何扫描Mapper接口的呢?
1. @Mapper注解的工作原理 : AutoConfiguredMapperScannerRegistrar
在每个Mapper接口上都打上@Mapper注解,mybatis-spring扫描到就会,如果没有配置@MapperScan,则会默认扫描与Springboot同层级的包下的@Mapper注解的接口。
注册MapperScannerConfigurer的Bean定义到Spring容器中,并设置扫描包的路径
MapperScannerConfigurer 实现BeanDefinitionRegistryPostProcessor接口,实例化的时候会调到postProcessBeanDefinitionRegistry方法,这个方法里会创建一个ClassPathMapperScanner对象,然后去扫描
扫描到之后修改BeanDefinition
1. @MapperScan注解的工作原理,其实和@Mapper扫描之后做的事情一样,只不过扫描的包为@MapperScan注解的basePackage的值,而且配置了@MapperScan,@Mapper将不再被支持。
@MapperScan注解,会import进来MapperScannerRegistrar这个类
MapperScannerRegistrar类实现ImportBeanDefinitionRegistrar接口,实例化的时候会调用registerBeanDefinitions方法
和@Mapper一样,同样会创建MapperScannerConfigurer的BeanDefition,用于后续实例化
只不过要扫描的包路径变了,不再是默认的,而是@MapperScan配置的包路径
后面的话则和@Mapper扫描到之后的工作原理是一样的,扫描到之后,更改BeanDefinition,一毛一样的。
==可以看出@MapperScan最主要的工作原理除了提供BasePackage的值之外,就是用@Import注解导入MapperScannerRegistrar.所以这个注解打在任何可以被spring扫描到的类上都可以,并不一定要打在启动类上(大多数为了只是为了看起来方便,把全局性的配置注解打在启动类上而已)==
2.为什么说配置了@MapperScan,@Mapper将不再被支持。
前面提到,注册扫描@Mapper接口的MapperScannerConfigurer实例的类是AutoConfiguredMapperScannerRegistrar,那么这个类是如何被导入进来的呢
MybatisAutoConfiguration还有一个静态内部类,@Import了AutoConfiguredMapperScannerRegistrar类,但是有@ConditionalOnMissingBean,即spring容器中不存在MapperFactoryBean,MapperScannerConfigurer的实例。
如果@MapperScan注解生效,并且扫描到任意一个Mapper接口(前面被改造成MapperFactoryBean类型的了),那么就不满足注册这个类MapperScannerRegistrarNotFoundConfiguration的实例的条件,继而不会导入AutoConfiguredMapperScannerRegistrar类。
这里就是熟悉的原生Mybatis创建Mapper接口的味道了。
附上调用的类时序图,回过头来看一下调用的整体流程。