Mybatis source analysis

Process analysis of MyBATIS

First of all, myBatis source code is divided into two cases:

  1. Separate mybatis
  2. And spring integration of mybatis source code

The source analysis is a little different in these two cases. For example, if you are analyzing myBatis + Spring schema, then mybatis starts from the initialization of Spring.

In the case of integrating Spring, where does MyBatis start

The first analysis is that the integration of MyBatis and Spring is mainly to provide two associations

  • @MapperScan
  • @Bean—->SqlSessionFactoryBean

Through the source MapperScan main actually use spring the Import of technology and the expansion of the spring point ImportBeanDefinitionRegistrar, and @ Bean is only an object using the javaconfig technology configuration. If you’re familiar with Spring, you know that the first import spring handles is the MapperScan

@MapperScan

If you are familiar with Spring and are familiar with the Spring initialization process, you know that there are roughly two parts to spring initialization

  1. Work before instantiating spring Beans
  2. Work in and after the Spring instance
Work before springBean instantiation

Analyzing the source code shows that @MapPerscan does three main things

  1. Scan out all beandefinitions of mapper.
  2. Make Mapper into FactoryBean, BeanDefinition of MapperFactoryBean
  3. Add a constructor value to BeanDefinition, because MyBatis’s MapperFactoryBean has a parameter constructor,

Spring needs a constructor value when instantiating this object. This value is a class from which Spring returns our proxy object during instantiation

# 1.Make mapper FactoryBean MapperScannerRegistrar. RegisterBeanDefinitions () ClassPathMapperScanner. DoScan () ClassPathMapperScanner.processBeanDefinitions()// This is where we pass the class to the constructor with a parameter
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
// Change all mapper interfaces to the MapperFactoryBean class
definition.setBeanClass(this.mapperFactoryBean.getClass());


public MapperFactoryBean(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
}

public T getObject(a) throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
}

# 2.Spring to instantiate the BeanDefinition ConstructorResolver. AutowireConstructor ()// Take the arguments passed to the constructor and get the mappeer interface passed
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

Copy the code
Work in and after Spring instantiation

Mybatis mainly uses spring’s initial method extension point to complete the initialization of mapper information, such as SQL statement initialization, here the spring extension point is mainly afterPropertiesSet, If you’re familiar with Spring, you’ll know how afterPropertiesSet works, which is to implement An initialzingBean using MapperFactoryBean. Since MapperFactoryBean is a FactoryBean, we understand it to be a Mapper, so we can understand it to get its own information and then cache it into a map. mappedStatements

org.apache.ibatis.session.Configuration#mappedStatements
org.springframework.dao.support.DaoSupport#afterPropertiesSet
org.mybatis.spring.mapper.MapperFactoryBean#checkDaoConfig
org.apache.ibatis.session.configuration#addMapper(this.mapperInterface); org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parse(); Org. Apache. Ibatis. Builder. The annotation. MapperAnnotationBuilder# parseStatement () key code SqlSource SqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);Copy the code

Related flow chart

Mybatis level 1 cache problems

1. Why is mybatis invalid when integrating spring level cache?

Because myBatis and spring’s integration package extend a class sqlSessionTemplate that is injected into Mapper when the Spring container starts. This class replaces DefaultSqlSession. All query methods in the SqlSessionTemplate are not directly queried, but instead go through a proxy object that enhances the query methods, primarily to close the session.

  • Underlying principle analysis:
  • In tracing the source code, you can see that the sqlSession has been changed to sqlSessionTemplate

*

  • Entering the sqlSessionTemplate class, you can see that the original DefaultSqlSession has been enhanced.
  • Tracing to the next step, you can see that the invocationHandler of the DefaultSqlSession proxy class (JDK dynamic proxy) has been accessed.

Compared to myBatis’ native Mapper query, you can see that the native query uses the DefaultSqlSession object

Summary: Source code analysis can see the principle of myBatis level 1 cache invalidation, is the enhancement of sqlSessionTemplate. Consider: Why do I need to close the sqlSession here?

After the integration of MyBatis and Spring, the Mapper managed by MyBatis is directly handed over to Spring management, but Mybatis does not expose sqlSession to Spring, so when Spring executes the code, it can not get sqlSession object. So spring has no choice but to close the sqlSession after execution.

How to initialize MyBatis after integrating Spring with Mybatis?

1. How does MyBatis scan the Mapper interface?

As discussed above, the integration of MyBatis and Spring leaves all of myBatis’s Mapper interfaces to MapperFactoryBean. MapperFactoryBean is a FactoryBean object, and the actual object returned is the object returned by the getObject() method.

  • Enter the source code analysis phase:
  • 1. Scan all mapper interfaces in myBatis using @mapperscan. Principle is to use spring’s import extension point (ImportBeanDefinitionRegistrar)
  • 2. Implements ImportBeanDefinitionRegistrar rewrite registerBeanDefinitions method, get the registry objects, can register beans into the spring container
  • 3. Start scanning for Mapper interfaces
  • 4. Process the scanned Mapper interface. Examples include adding properties, setting autoload mode, changing beanClass, adding constructor parameters, and so on.

Summary: this is mainly for mapper interface initialization work, most have 3 effects. 1. Use the @mapPERScan annotation and import technology to perform mapper scanning. 2. Change the scanned Mapper to beanClass and use FactoryBean for unified processing. 3. Change the auto-assembly mode of beanDefinition, so that the properties of MapperFactoryBean object can be auto-assembly without using @autowired, avoiding the mandatory dependence on Spring.

How to instantiate Mapper interface in MyBatis?
  • 1. Assign values to the MapperFactoryBean object attribute of the Mapper interface.

By looking at MapperFactoryBean, you can see the related properties. For a moment, we assume that the following properties need to be auto-assembled: 1.mapperInterface 2.addToConfig 3.setSqlSessionFactory() 4.setSqlSessionTemplate()

  • The following is analyzed by tracing the source code:
  • Then trace to the autowireByType method.

Summary: MapperFactoryBean needs auto-assembly properties: sqlSessionFactory, addToConfig

  • 2. After MapperFactoryBean interface is instantiated, how to scan the sqL. XML or annotations corresponding to the Mapper interface?

Implement the InitializingBean interface, override the afterPropertiesSet() method, and initialize in that method. Question: Why not use @PostConstruct instead of implementing the InitializingBean interface?

By implementing the InitializingBean interface, we override the afterPropertiesSet() method, which, as the name implies, does not execute until all Properties are initialized. So the initialization of myBatis is to wait until all attributes are initialized, then initialize the contents of myBatis, such as: scan mapper and other operations.

Look at the structure of MapperFactoryBean: MapperFactoryBean – > SqlSessionDaoSupport – > DaoSupport – > impl InitializingBean all can get MapperFactoryBean, InitializingBean interface is implemented.

InitializingBean is a Spring technology that implements this class and needs to override the afterPropertiesSet() method. AfterPropertiesSet (), as the name implies, is executed after all property auto-assembly of the class.

  • Tracking source analysis:

Spring and MyBatis integration summary

All of the key points for integrating MyBatis into Spring have been shared here. The key point to summarize: 1. @ MapperSacn, import, ImportBeanDefinitionRegistrar 2. FactoryBean, InitializingBean, AutowireMode