The plug-in mechanism of mybatis

Posted by hustler on Sun, 03 Nov 2019 13:27:50 +0100

I. Introduction to mybatis plug-in

As for the plugins of mybatis, I think you've used them, such as the most commonly used reverse engineering, which generates model, dao, xml files and paging plugins according to the table structure. What's the working principle of these plugins, such as paging plugins? Why can it change the sql statements we write in xml files? This article will bring you to understand the plugins mechanism of mybatis. (as I am also learning, there are inevitably mistakes or shortcomings in this article. I hope to correct them. This article is based on mybatis version 3.3.0). The following will focus on these aspects

1. Plug in entry, that is, how to inject plug-ins into mybatis code

2. What classes or methods can plug-ins intercept

3. Principle of simple table dividing plug-in with examples

II. Plug in entry

Before we know about it, let's customize the mybatis plug-in

 1 import org.apache.ibatis.executor.statement.StatementHandler;
 2 import org.apache.ibatis.plugin.*;
 3 
 4 import java.sql.Connection;
 5 import java.util.Properties;
 6 
 7 @Intercepts(
 8         value = {
 9                 @Signature(
10                         type = StatementHandler.class,
11                         method = "prepare",
12                         args = {Connection.class} // Different versions of the prepare method have different parameters. There is also an Integer parameter in the higher version
13                 )
14         }
15 )
16 public class PluginDemo implements Interceptor {
17     @Override
18     public Object intercept(Invocation invocation) throws Throwable {
19         return invocation.proceed();
20     }
21 
22     @Override
23     public Object plugin(Object target) {
24         return Plugin.wrap(target,this);
25     }
26 
27     @Override
28     public void setProperties(Properties properties) {
29 
30     }

 

To customize the mybatis plug-in, you must implement the Interceptor interface, which has three abstract methods

1. intercept, which is the core method of mybatis. To implement custom logic, this method is basically modified. The invocation parameter can obtain the original method and corresponding parameter information through reflection

2. Plugin, which is used to generate an intercepting object, that is, a proxy object, so that the proxy object will pass through the intercept method, usually using the tool class plugin provided by mybatis to obtain the proxy object. If you have your own unique requirements, you can define it yourself

3. setProperties. This method is used to set some properties of the plug-in

The @ intercepts annotation is used to indicate which classes and methods are intercepted.

When we leave the spring container to use mybatis, we usually write code like this

 

 

In the mybatisConfig.xml file, we have configuration database connection information, plug-ins, aliases, mapper file mapping address and other information. (warm tip, these configurations are in a certain order. If they are not configured in order, mybatis will throw an exception when parsing. For detailed configuration information, please refer to the dtd file configuration of mbatis.) since they are configured in the configuration file, they must also It will be resolved, as shown in the figure below, in XmlConfigBuild

 

After parsing, the plug-in information will be stored in the InterceptorChain collection of configuration. This configuration is a single example in mybatis operation cycle, which is responsible for storing all configuration information

 

 

 

 

Finally, mybatis plug-in information is completely injected into the configuration.

What classes or methods can mybaits plug-in intercept

In the normal development process, we basically obtain the sqlsession first. If we don't use the custom configuration, the default sqlsession implementation is defaultSqlSession. There is a fusion plug-in implied in a method of this class,

The executor will be obtained. This class is obtained through configuration,

 

The final way to fuse plug-ins is the code in the red box in the figure. It generates a proxy class for the original executor class. So when you execute some methods of executor class, such as query and update methods, they will be the corresponding proxy objects. myabtis uses the dynamic proxy of jdk. After the proxy, when you execute the query and update methods of executor class, they will be automatically transferred to your customized plug-in intercept method, which can also be understood as overwriting the original method.

Through this, we can probably guess the class that the mybatis plug-in wants to intercept. This is mainly because it is generated in the configuration class. I won't take you around. Let's take a look at the screenshot

Intercepts the implementation class of statementHandler interface, which implements routing through routingStatementHandler, and finally directs to prepareStatementHandler class

Intercept parameterHandler. This interface is used to encapsulate parameters, that is, to set parameters into sql

 

Intercepts the ResultSetHandler interface, which is mainly used to process the results returned by sql operation

 

 

In summary, mybatis can intercept four classes

I. executor and executor class can be said to be the whole process of executing sql, such as assembly parameters, sql transformation, result processing, which are relatively extensive, but they are seldom used in practice

2. StatementHandler, this is the process of executing sql. You can get the sql to be executed, which can be used to modify sql, such as paging, table splitting, and the most commonly intercepted class

3. paremeterHandler, which is used to intercept sql parameters. You can customize parameter assembly rules

4. resultHandler, which is used to process results

III. simple version of table dividing plug-in

 1 import org.apache.ibatis.executor.statement.StatementHandler;
 2 import org.apache.ibatis.mapping.BoundSql;
 3 import org.apache.ibatis.plugin.*;
 4 import org.apache.ibatis.reflection.MetaObject;
 5 import org.apache.ibatis.reflection.SystemMetaObject;
 6 
 7 import java.sql.Connection;
 8 import java.util.Properties;
 9 
10 @Intercepts(
11         value = {
12                 @Signature(
13                         type = StatementHandler.class,
14                         method = "prepare",
15                         args = {Connection.class}
16                 )
17         }
18 )
19 public class PluginDemo implements Interceptor {
20     @Override
21     public Object intercept(Invocation invocation) throws Throwable {
22 
23         /**
24          * Get the current class that is blocked. In this case, statementHandler is blocked. All current classes are it
25          * Through this class, we can get the sql statements to be executed. Usually we use mataObject tool class to get them
26          * You can learn about this tool class by yourself. I think this tool class is very powerful
27           */
28         StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
29         MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
30         /**
31          * First explain why you can get the boundSql class by writing it as delegate.boundSql
32          * As you can see earlier, the default implementation of statementHandler is routingStatementHandler.
33          * This class has a property statementHandler, the property name is delegate, and the default implementation of this property is preparedStatementHandler
34          * The latter class also has the attribute boundSql, so the final writing method is delegate.boundSql.
35          * Therefore, this also reflects the power of the MetaObject tool class. You can get the corresponding property value according to the property name by instance parameter passing
36          */
37         BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
38 
39         // Execu sql,Here is the pre compiled translation sql,That is, all the parameters are?Number
40         String sql = boundSql.getSql();
41         /**
42          * Now that you have the pre compiled sql, you can do whatever you want, such as paging, dividing tables by year, etc
43          * In the case of separate tables, I recommend druid's sql parser. I think it's still good. You can learn about it by yourself
44          * Do not forget to set it back
45          * metaObject.setValue("delegate.boundSql.sql",sql);
46          *  invocation.proceed,Execution of the original method
47          *  Note that since the mybatis plug-in adopts the proxy mode, if there are multiple plug-ins, multiple proxies will be formed
48          *  If you want to get the most primitive object, you have to decompose it further
49          *  For example: while (metaobject. GetValue ("" H)! = null){
50          *      Object obj = metaObject.getValue("h");
51          *       ....
52          *  }
53          */
54         return invocation.proceed();
55     }
56 
57     @Override
58     public Object plugin(Object target) {
59         return Plugin.wrap(target,this);
60     }
61 
62     @Override
63     public void setProperties(Properties properties) {
64 
65     }
66 }

 

Boundary line-------------------------------------------------------------------------------------

That's all

Topics: Java SQL Mybatis Apache