Today’s sharing started, please give us more advice ~

In MyBatis, we will take a look at how Spring integrates MyBatis. Let everyone thoroughly master the underlying design principle and realization of MyBatis.

MyBatis integrates Spring principles

MyBatis integration into Spring is to further simplify the use of MyBatis, so it only makes some encapsulation of MyBatis, without replacing the core object of MyBatis. MyBatis jar package SqlSessionFactory, SqlSession, MapperProxy classes will be used. The classes in mybatis-spring. Jar just do some wrapping or bridging work.

Once we understand how these three objects are created, we can understand how Spring inherits MyBatis. Let’s break it down into three steps:

  1. Where the SqlSessionFactory was created.
  2. Where SqlSession is created.
  3. Where the proxy class is created.

1 SqlSessionFactory

First let’s look at the process of creating SqlSessionFactory in MyBatis Integration Spring. Check this step in the Spring configuration file configuration integration TAB

SqlSessionFactoryBean implements InitializingBean, FactoryBean and ApplicationListener

1.1 the afterPropertiesSet

Let’s start by looking at the logic in the afterPropertiesSet method

You can see that the buildSqlSessionFactory method is called directly in afterPropertiesSet to create the sqlSessionFactory object

The SqlSessionFactory object has been created in the afterPropertiesSet method, and related configuration files and mapping files have been parsed.

Method summary: By defining a SqlSessionFactoryBean class that implements the InitializingBean interface, an afterPropertiesSet() method is called when the bean property value is set. Spring completes the parsing and factory class creation when it initializes the Bean.

1.2 getObject

Additionally, SqlSessionFactoryBean implements the FactoryBean interface.

The purpose of a FactoryBean is to allow users to customize the logic for instantiating the Bean. If you get a Bean from a BeanFactory based on its Bean ID, it actually gets the object returned by getObject() of a FactoryBean.

That is, when we get the SqlSessionFactoryBean, we call its getObject() method.

The logic in the getObject method is very simple, returning the SqlSessionFactory object, and calling afterPropertiesSet once more to parse and create it if the SqlSessionFactory object is empty.

1.3 onApplicationEvent

Implementing the ApplicationListener interface gives SqlSessionFactoryBean the ability to monitor event notifications emitted by the application. For example, the ContextRefreshedEvent (context refresh event) is listened on, which is executed after the Spring container has loaded. What you’re doing here is checking to see if the MS is loaded.

2 SqlSession

2.1 DefaultSqlSession Problems

SqlSessionFactory DefaultSqlSession = SqlSessionFactory DefaultSqlSession = SqlSessionFactory DefaultSqlSession is thread unsafe. Therefore, there will be data security problems in direct use, for this problem, in the integration of MyBatis-Spring plug-in package to provide us with a corresponding tool SqlSessionTemplate.

We use try catch blocks whenever we use SqlSession

The SqlSessionTemplate provided in Integrated Spring simplifies operations and provides secure handling.

2.2 SqlSessionTemplate

The mybatis- Spring package provides a thread-safe WRAPPER class to replace SqlSession. This class is called the SqlSessionTemplate. Because it is thread-safe, one instance can be shared across all DAO layers (singleton by default).

The SqlSessionTemplate, like DefaultSqlSession, defines selectOne(), selectList(), Insert (), update(), delete(), and so on, but does not have its own implementation. The methods of a proxy object are all called.

So where does the SqlSessionProxy come from? The answer is in the constructor of the SqlSessionTemplate

The SqlSessionInterceptor invoke method should be accessed from above.

The above code, while somewhat complex, is essentially what follows

Key code in the getSqlSession method:

Execute the process

To sum up: Since DefaultSqlSession itself cannot generate a new instance every time a request is called, we simply create a proxy class that implements SqlSession and provides the same methods as DefaultSqlSession. Each time a method is called, an instance of DefaultSqlSession is created and the corresponding method of the propped object is called.

MyBatis also comes with a thread-safe implementation of SqlSession: SqlSessionManager, which is implemented in the same way as Spring.

2.3 SqlSessionDaoSupport

We should add the SqlSessionTemplate to the IoC container first. Then we should fetch the SqlSessionTemplate in Dao via @autoWired:

Then we can look at the code in SqlSessionDaoSupport

So at the Dao level we just need to inherit SqlSessionDaoSupport and operate directly with the getSqlSession method.

That is, we have the DAO layer (implementation class) inherit the abstract class SqlSessionDaoSupport and automatically have the getSqlSession() method. Call getSqlSession() to retrieve the shared SqlSessionTemplate.

Execute SQL in the DAO layer in the following format:

Still not concise enough. To reduce duplicate code, we usually create a BaseDao extension of SqlSessionDaoSupport instead of having our implementation class directly inherit SqlSessionDaoSupport. BaseDao encapsulates operations on the database, including selectOne(), selectList(), Insert (), and delete(), which subclasses can call directly.

Then let our DAO layer implement classes that inherit from BaseDao and implement our Mapper interface. The implementation class needs to be annotated with @repository.

In the implementation class’s methods, we can call the selectOne() method wrapped in the parent class (BaseDao) directly, which will eventually call the selectOne() method of the sqlSessionTemplate.

We then inject our implementation class where we need to use it, such as the Service layer, and call the implementation class’s methods. We inject daoSupportTest.java directly into the unit test class:

The DefaultSqlSession method is eventually called.

2.4 MapperScannerConfigurer

SqlSessionTemplate/SqlSessionDaoSupport = SqlSessionDaoSupport = SqlSessionDaoSupport = SqlSessionDaoSupport = SqlSessionDaoSupport = SqlSessionDaoSupport = SqlSessionDaoSupport How exactly does this work? In addition to SqlSessionFactoryBean, you can add MapperScannerConfigurer to the MyBatis configuration file.

The first is the inheritance structure of MapperScannerConfigurer

MapperScannerConfigurer BeanDefinitionRegistryPostProcessor interface is realized. BeanDefinitionRegistryPostProcessor is a subclass of spring BeanFactoryPostProcessor, there is a postProcessBeanDefinitionRegistry () method.

Implementing this interface lets you change the definition of some beans in the container before Spring creates them. Spring calls this method before creating the Bean.

At the heart of the above code is the Scan method

The doScan method in subclass ClassPathMapperScanner is then called

Since an interface can’t create instance objects, we point the interface type to a specific generic Java type, MapperFactoryBean, before creating the object. That is, all Mapper interfaces are registered in the container as a generic MapperFactoryBean. The MapperFactoryBean object is then created when you create the object for this interface.

2.5 MapperFactoryBean

Why register for it? So when injection is used, it’s also this object, what does this object do? First, take a look at their class diagram structure

As you can see from the class diagram, MapperFactoryBean inherits SqlSessionDaoSupport, so every time Mapper is injected, you can get the SqlSessionTemplate object. Then we also find that MapperFactoryBean implements the FactoryBean interface, which means that when you inject a MapperFactoryBean object into the container, you essentially inject the return object from getObject into the container.

It does not return a MapperFactoryBean directly. Instead, the getMapper() method of the SqlSessionTemplate is called. The SqlSessionTemplate is essentially a proxy, so it will eventually call the getMapper() method of DefaultSqlSession. We are not going to repeat the following process. That is, a JDK dynamic proxy object is returned.

So any method that ends up calling the Mapper interface is the invoke() method of the MapperProxy, and the flow is exactly the same as in programmatic engineering.

To summarize, how does Spring inherit MyBatis?

  1. SqlSessionTemplate provides a substitute for SqlSession, which has an internal SqlSessionTemplate implementation implementation of InvocationHandler, is essentially a proxy for SqlSession.
  2. SqlSessionDaoSupport provides an abstract class to get the SqlSessionTemplate.
  3. MapperFactoryBean, which inherits SqlSessionDaoSupport, obtains the SqlSessionTemplate by scanning the Mapper interface.
  4. When Mapper is injected, the getObject() method is called, which actually calls the getMapper() method of the SqlSessionTemplate, injecting a JDK dynamic proxy object.
  5. Executing any method of the Mapper interface triggers the management class MapperProxy and enters the SQL processing flow.

Core objects:

Finally, summarize the relevant design patterns used in the source code of MyBatis:

Well, Spring integration MyBatis principle analysis is introduced here.

Today’s share has ended, please forgive and give advice!