Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.


We widely use MyBatis as data persistence layer framework in our daily work, but what is the implementation process of MyBatis? Have you learned about it? This article will take you to analyze the working principle of Mybatis from the source point of view.

Mapper = Mapper; Mapper = Mapper;

public interface StudentMapper {
    @Select("select * from student")
    public List<Map<String,Object>> query();
}
Copy the code

Call Mapper’s methods in Servie:

@Service("studentService")
public class StudentServiceImpl implements StudentService {
    @Autowired
    StudentMapper studentMapper;

    @Override
    public List<Map<String, Object>> query() {
        returnstudentMapper.select(); }}Copy the code

When you inject this Mapper into a Service and call it, do you know what you’re injecting?

After debugging, you can see that the actual studentMapper is a proxy object whose type is MapperProxy. The following describes how to generate the proxy object from the initialization of myAbtis.

What is done when SqlSessionFactoryBean is configured?

When spring and MyBatis are integrated, an SqlSessionFactoryBean will be configured using XML or annotations.

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
   SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
   sqlSessionFactoryBean.setDataSource(dataSource);
   return  sqlSessionFactoryBean;
}
Copy the code

Take a look at the inheritance implementation of SqlSessionFactoryBean:

Let’s start with two very important interfaces in Spring, FactoryBean and InitializingBean.

FactoryBean:

A FactoryBean is a special spring Bean that returns an instance of an object through its getObject() method. An implementation of the getObject() method in SqlSessionFactoryBean:

This is used to create and return an SqlSessionFactory. In Spring + Mybatis, we use SqlSessionFactoryBean to act as the SqlSessionFactory.

InitializingBean:

There is only one method in the InitializingBean interface, afterPropertiesSet(), which is called by all classes that implement the interface before the bean is initialized. As you can see from the getObject method above, if the SqlSessionFactory is empty, this method is called to create the SqlSessionFactory.

Calling the build method of SqlSessionFactoryBuilder finally returns an instance of DefaultSqlSessionFactory, The DefaultSqlSessionFactory holds a very important Configuration object.

What does @Mapperscan do?

When configuring Mybatis with annotations, you can automatically implement the interface as a class for us by specifying the package that Mapper stores via @mapperscan. So how does this work?

If you open the @mapperscan source code, there is a very important note on it:

@Import(MapperScannerRegistrar.class)
Copy the code

ImportBeanDefinitionRegistrar interface provides to users exposed the BeanDefinitionRegistry registerBeanDefinitions method, That is, you can have the user manually create a BeanDefinition and register it with the Spring container using the registry.

Look at the core code in the registerBeanDefinitions method at MappercannerRegistrar:

ClassPathMapperScanner scanner = newClassPathMapperScanner(registry); ... scanner.doScan(StringUtils.toStringArray(basePackages));Copy the code

Basically create a Mapper scanner and start scanning. Take a look at the doScan method in ClassPathMapperScanner:

The bean definition for the generated Mapper is further processed here. Enter processBeanDefinitions() method:

Take a look at the initial beanClass value when you get BeanDefinitionHolder from BeanDefinitionHolder.

Wait for setBeanClass to finish executing:

Definition. SetBeanClass () replaces the original BeanClass type with the MapperFactoryBean type. This completes a very important step in the Mapper interface loading definition phase, which is also the key to generating the proxy object MapperProxy.

Mybatis how to generate proxy objects?

Take a look at the inheritance of MapperFactoryBean:

The SqlSessionDaoSupport class inherited from MapperFactoryBean implements the InitializingBean interface, so let’s first look at the afterPropertiesSet() method:

DaoSupport finally calls the method in MapperFactoryBean:

Get the very important Configuration class Configuration by getting the sqlSession, then look at the addMapper method, and finally call the addMapper method of MapperRegistry:

The code in the red box creates Mapper’s proxy factory object for us (not yet Mapper’s proxy object) and puts it into knownMappers, a Map.

In this step, we simply initialize the MapperProxyFactory, passing in our own Mapper type, without actually generating a proxy object.

MapperRegistry then parses the XML file in the parse() method. Each SQL method is parsed into a MappedStatement object and added to the Configuration class Configuration object.

What does the MapperFactoryBean ultimately return?

Since MapperFactoryBean implements the FactoryBean interface, let’s see what the getObject method actually returns:

Finally call MapperRegistry’s getMapper method:

This calls the MapperProxyFactory mybatis just generated to help us instantiate and return a proxy object.

NewInstance is used to instantiate MapperProxy in MapperProxyFactory to generate proxies:

So far, we have seen how MapperProxy was generated at the beginning of this article.

How does MapperProxy execute SQL statements?

Enter a breakpoint trace statement in the Query method of StudentServiceImpl and you will see that the invoke() method of the proxy class MapperProxy is actually executed.

MapperProxy implements the InvocationHandler interface while acting as a proxy class, so the Invoke method is the actual proxy logic that executes.

This is where the MapperMethod’s execute method is finally called to actually execute the SQL statement.

In this method, according to the SQL statement execution type, the method corresponding to sqlSession is called to execute and the result is returned to the user. At this point, the next call of Mybatis in spring environment is complete.

The last

If you think it is helpful, you can like it and forward it. Thank you very much

Public number agriculture ginseng, add a friend, do a thumbs-up friend ah