编程知识 cdmana.com

Master the principle of mybatis plug-in and write your own PageHelper plug-in easily

Preface

When it comes to plug-ins , I'm sure you all know that , The existence of plug-ins is mainly used to change or enhance the original function ,MyBatis The same in China .

However, if we are right MyBatis If you don't know how it works , It's better not to use plug-ins easily , Otherwise, if the underlying working logic is changed due to the use of plug-ins , There are likely to be a lot of unexpected problems .. Tidy up 100+ individual Java Project video + Source code + note

This article mainly introduces MyBatis The use of plug-ins and their implementation principles , I believe that after reading this article , We can also write our own PageHelper Paging plug-in .

MyBatis How is the plug-in implemented in

stay MyBatis Plug in through the interceptor to achieve , So since it's implemented by interceptors , There will be a problem , Which objects are allowed to be intercepted ?

True execution Sql There are four objects :Executor,StatementHandler,ParameterHandler,ResultSetHandler.

and MyBatis This is based on the four plug-ins . It should be noted that , Although we can intercept these four objects , But not all the methods in these four objects can be intercepted , The following is a summary of interceptable objects and methods provided by the official website :

MyBatis Use of plug-ins

First, let's take an example to see how to use plug-ins .

1、 So let's set up a MyPlugin Implementation interface Interceptor, And then rewrite three of them ( Be careful , It has to be realized here Interceptor Interface , Otherwise, it can't be intercepted ).

package com.lonelyWolf.mybatis.plugin;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.Properties;

@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})})
public class MyPlugin implements Interceptor {

    /**
     *  This method will directly override the original method 
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println(" Successfully intercepted Executor Of query Method , There's something I can do here ");
        return invocation.proceed();// Call the original method 
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target,this);// Generate a proxy object from the intercepted object 
    }

    @Override
    public void setProperties(Properties properties) {// Some properties can be customized 
        System.out.println(" Custom properties :userName->" + properties.getProperty("userName"));
    }
}

@Intercepts Is to declare that the current class is an interceptor , hinder @Signature Is to identify the method signature that needs to be intercepted , It is determined by the following three parameters

(1)type: The name of the intercepted class

(2)method: Intercepted method name

(3)args: Parameter types of annotation methods

2、 We still need to mybatis-config Configure plug-ins in .

<plugins>
    <plugin interceptor="com.lonelyWolf.mybatis.plugin.MyPlugin">
        <property name="userName" value=" Zhang San "/>
    </plugin>
</plugins>

Here, if it's configured property attribute , So we can do that setProperties Get .

Complete the above two steps , We have completed the configuration of a plug-in , Let's run it :

You can see ,setProperties Method is executed during the load configuration file phase .

MyBatis Plug in implementation principle

Next, let's analyze the implementation principle of the whole process from plug-in loading to initialization to running .

Plug in loading

Since the plug-in needs to be configured in the configuration file , Then it must be analyzed , Let's see how plug-ins are parsed . We enter XMLConfigBuilder Class look

After parsing, the plug-in will be saved InterceptorChain Object's list attribute

notice InterceptorChain Can we think of ,MyBatis The plug-in of is realized through the responsibility chain mode .

How the plug-in intercepts

Now that the plug-in class has been loaded into the configuration file , Then there's a question , When will plug-in classes be intercepted? The objects we need to intercept ?

In fact, the interception of plug-ins is related to objects , The interception time of different objects will be inconsistent , Let's analyze it one by one .

Intercept Executor object

We know ,SqlSession The object is through openSession() Method , and Executor It belongs to me again SqlSession Internal object , So let's follow openSession Way to see Executor Object initialization process .

You can see , When initialization is complete Executor after , Would call interceptorChain Of pluginAll Method ,pluginAll The method itself is very simple , It's saving us to list The plug-in in , And call Interceptor Object's plugin Method :

Click in again : Do we find that we are familiar with , you 're right , This is the method we rewritten in the example above , and plugin Method is a default method in the interface .

This method is the key , Let's go in and have a look :

You can see that the logic of this method is also very simple , But here's the thing MyBatis Plug in is through JDK Dynamic agent to achieve .

and JDK The condition of dynamic proxy is that the proxy object must have an interface , This and Spring It's different in ,Spring If there is an interface, use JDK A dynamic proxy , No interface, just use CGLIB A dynamic proxy .

It is because MyBatis The plug-in only uses JDK A dynamic proxy , That's why we emphasized above that we must realize Interceptor Interface .

After the star of convergence Plugin Of invoke Method , Let's take a final look invoke Method :

And the final execution is intercept Method , This is the method we rewritten in the example above .

Other object plug-in parsing

Let's take a look at StatementHandler,StatementHandler Is in Executor Medium doQuery Method to create , In fact, the principle is the same , Found initialization StatementHandler Object method : After going in, the execution inside is also pluginAll Method :

The other two objects are not examples , In fact, if you look at the whole situation, it will be obvious : All four objects are called when they are initialized pluginAll To determine whether there is a proxy .

Plug in execution process

The following is the execution sequence diagram after the plug-in is implemented :

If an object is represented many times

Whether an object can be represented by multiple proxy objects ? In other words, whether the same method of the same object can be intercepted by multiple interceptors ?

The answer is yes , Because the proxy object is added to list, So the interceptor we configured at the front is the first to be proxied , But when it's executed, it's the outermost layer that is executed first .

Be specific :

If you define three plug-ins in turn : plug-in unit A, plug-in unit B and plug-in unit C.

that List It will be stored in order : plug-in unit A, plug-in unit B and plug-in unit C.

And parsing is traversal list, So the analysis is based on : plug-in unit A, plug-in unit B and plug-in unit C The order of .

But when it comes to execution, it has to be reversed , It is carried out according to : plug-in unit C, plug-in unit B And plug-ins A In order to execute .

PageHelper Use of plug-ins

We learned above that in MyBatis How to define plug-ins in and MyBatis How plug-ins are handled in , Next, let's take the classic paging plug-in PageHelper As an example to further understand .

First of all, let's see PageHelper Usage of :

package com.lonelyWolf.mybatis;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lonelyWolf.mybatis.mapper.UserMapper;
import com.lonelyWolf.mybatis.model.LwUser;
import org.apache.ibatis.executor.result.DefaultResultHandler;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisByPageHelp {
    public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        // Read mybatis-config The configuration file 
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // establish SqlSessionFactory object 
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // establish SqlSession object 
        SqlSession session = sqlSessionFactory.openSession();

        PageHelper.startPage(0,10);
        UserMapper userMapper = session.getMapper(UserMapper.class);
        List<LwUser> userList = userMapper.listAllUser();
        PageInfo<LwUser> pageList = new PageInfo<>(userList);
        System.out.println(null == pageList ? "": JSONObject.toJSONString(pageList));

    }
}

The output is as follows : You can see that the object has been paginated , So how does this work ?

PageHelper Plug in principle

We mentioned above , To implement a plug-in, you have to implement MyBatis Provided Interceptor Interface , So let's find out , Find out PageHeler Realized Interceptor:

After the introduction above, this class should be able to understand at a glance , The key is to see SqlUtil Of intercept What does the method do :

This method has more logic , Because different database dialects need to be considered , So there will be a lot of judgment , We mainly focus on PageHelper Where did you rewrite sql sentence , The red box in the picture above is a rewriting of sql Where the words are :

There's going to be a Page object , And then write in love sql Some paging parameters will also be set to Page object , Let's see. Page Where is the object obtained from : We see objects from LOCAL_PAGE Object , What is this ?

This is a local thread pool variable , So what's in here Page When did you put it in ? So we're going back to our example , The beginning of the paging must call :

PageHelper.startPage(0,10);

Here we'll build a Page object , And set it to ThreadLocal Inside .

Why? PageHelper Only right startPage The first one after select Statement is valid

This is actually very simple , But there may be people who think , We still have to go back up there intercept Method :

stay finally Inner handle ThreadLocal The paging data in is cleared , So once a query is executed, the paging information will be cleared , So the following select The sentence is naturally invalid .

Can it be changed without plug-ins MyBatis The core behavior of

Above, we introduced how to change through plug-ins MyBatis The core behavior of , Can it be implemented without plug-ins ?

The answer is yes , The website says , To achieve this, we can change the class configuration MyBatis Core behavior , In other words, we write a class inheritance Configuration class , And then implement the method , Finally build SqlSessionFactory The custom object is passed in Configuration Method :

SqlSessionFactory build(MyConfiguration)

Of course , This method is not recommended , Because it's like taking out the foundation and rebuilding the house , A bit careless , The house is about to collapse .

summary

This article mainly introduces MyBatis The use of plug-ins and MyBatis How it works , Finally, we also give a general introduction to PageHelper The main implementation principle of plug-ins , I believe that after reading this article, I will learn MyBatis After the plug-in principle , We can also write a simple one of our own PageHelper Paging plug-in . Other equipment . Tidy up 100+ individual Java Project video + Source code + note

版权声明
本文为[Java Architect]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224141846080q.html

Scroll to Top