Deep parsing: understand how MyBatis is initialized in the Spring container

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.

 

Tags: Java Programming Spring Boot

Posted on Sun, 05 Dec 2021 02:38:20 -0500 by capslock118