The initialization process of MyBatis is to generate some necessary objects and put them into the Spring container. The question is what objects are generated by this process? When MyBatis initialization fails, how to correctly find the entry point to analyze the problem? This paper will introduce these problems.
Based on MyBatis 3 and Spring, this article assumes that readers already know how to use Maven and MyBatis and understand the container mechanism of Spring.
1, Mybatis three piece set
We know that the main functions of MyBatis are provided by SqlSessionFactory and Mapper. Initializing MyBatis is to initialize these two types of objects. In addition, DataSource is also essential as a database access object. Therefore, first of all, we should remember the core three piece set of MyBatis initialization:
- DataSource: it is a necessary data source object to access the database. If this initialization fails, you cannot directly access the database.
- SqlSessionFactoryBean: This is the encapsulation of the SqlSessionFactory initialization process in the Spring container.
- Mappercannerconfigurer: This is the encapsulation of Mapper initialization process in the Spring container.
Specifically, a simple initialization process is as follows:
@Configuration public class SpringMyBatisApplication { public static void main(String[] args) { new AnnotationConfigApplicationContext(SpringMyBatisApplication.class); } @Bean public DataSource dataSource() { return ...; } @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) { return ...; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { return ...; } }
Next, we will introduce how to initialize the three piece set. The following contents can be operated practically. You might as well try it.
1. DataSource initialization
First, we create an empty Maven project and add the following dependencies in pom.xml:
<!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- database --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.199</version> </dependency>
This article focuses on demonstrating the initialization process of MyBatis, so there is no complex SQL, and the database uses an embedded database h2.
And then we were com.hyd.mybatis3test Create one under the package SpringMyBatisApplication Class, the code was given earlier.
The corresponding DataSource initialization is implemented as follows:
@Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:mem:test"); return dataSource; }
2. SqlSessionFactoryBean initialization
SqlSessionFactoryBean encapsulates the SqlSessionFactory initialization process. Spring will execute this initialization process at an appropriate time to get the final SqlSessionFactory object.
The creation process of SqlSessionFactoryBean is as follows (note that the method signature is changed based on the above):
@Bean public SqlSessionFactoryBean sqlSessionFactory( DataSource dataSource, ResourcePatternResolver resolver ) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(resolver.getResources("classpath*:mappers/*.xml")); return bean; }
Of which:
- The first parameter dataSource is the previously generated data source object;
- The second parameter resolver is automatically provided by Spring and is used to search all xml files under the specified path. This article will not contain xml files, so this configuration is invalid. This line can not be written, but it will not affect the operation of the program.
3. Mappercannerconfigurer initialization
Mappercannerconfigurer is responsible for searching all Mapper interface classes under the specified path (refer to its
postProcessBeanDefinitionRegistry() Method) and register it in MapperRegistry through MapperFactoryBean.
@Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer configurer = new MapperScannerConfigurer(); configurer.setBasePackage("com.hyd.mybatis3test"); return configurer; }
4. Verify that the initialization process is successful
To verify that the above initialization process is complete, we com.hyd.mybatis3test Create a Mapper class under the package:
@Mapper public interface SampleMapper { @Update("create table if not exists user(id int)") void createUserTable(); }
And a Service class:
@Service public static class SampleService { @Autowired private SampleMapper sampleMapper; @PostConstruct public void init() { sampleMapper.createUserTable(); } }
Then don't forget to add one on top of the Spring mybatisapplication @ ComponentScan("com.hyd.mybatis3test") Annotation, otherwise Spring will not find SampleService.
function
SpringMyBatisApplication.main() method, we can find such content in the output:
... SampleMapper.createUserTable - ==> Preparing: create table if not exists user(id int) SampleMapper.createUserTable - ==> Parameters: SampleMapper.createUserTable - <== Updates: 0 ...
This indicates that the SQL statement to create the table was executed successfully.
On the basis of the previous three-piece set, MyBatis also provides more packaging. With the foreshadowing above, I believe readers will be much easier to understand these packaging methods.
2, @ MapperScan annotation
@Mappercan annotation is just the initiator of mappercannerconfigurer. Using this annotation can replace the previous mappercannerconfigurer initialization.
3, SpringBoot auto initialization
Provided by MyBatis
The mybatis Spring Boot starter library is used to automatically initialize in the Spring Boot project:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
This so-called automatic initialization is actually initialization SqlSessionFactory Object. The initialization process is performed by
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration After completion, the required configurations are obtained from the configuration attribute of "mybatis -" prefix. For details, please refer to
org.mybatis.spring.boot.autoconfigure.MybatisProperties class.
summary
In short, the core initialization process of MyBatis is the initialization of the three piece set. In the Spring Boot application, combined with automatic initialization and @ MapperScan annotation, we can get Mapper objects directly from the container without manually initializing these three pieces.