mybatis的使用及源碼分析(六) mybatis自定義plugin

使用Mybatis的時候,會使用到各種插件,如PageHelper(分頁插件)等,下面介紹自定義plugin的方法

Mybatis插件又稱攔截器,Mybatis採用責任鏈模式,通過動態代理組織多個插件(攔截器),通過這些插件可以改變Mybatis的默認行爲。MyBatis 允許你在已映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis允許使用插件來攔截的方法調用包括:

Executor (update, query, flushStatements, commit, rollback,getTransaction, close, isClosed) 攔截執行器的方法;
ParameterHandler (getParameterObject, setParameters) 攔截參數的處理;
ResultSetHandler (handleResultSets, handleOutputParameters) 攔截結果集的處理;
StatementHandler (prepare, parameterize, batch, update, query) 攔截Sql語法構建的處理;

自定義一個Plugin:
本項目搭建源碼:https://github.com/zhuquanwen/mybatis-learn/releases/tag/with-plugin
搭建過程:
https://blog.csdn.net/u011943534/article/details/104911104文章基礎上搭建,有些過程不詳細描述.

1、自定義一個類實現Interceptor

Signature註解中 type支持上面說的四種類型:Executor、ParameterHandler、ResultSetHandler、StatementHandler,method對應某個type類型中的方法名 ,args是方法參數的類對象。
plugin方法,默認使用Plugin.wrap(target, this)就好,setProperties可以注入配置參數,intercept可以做一些業務處理,比如這裏我把SQL語句輸出,把耗時計算輸出。

package com.learn.zqw.plugin;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
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;

/**
 * //TODO
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/6/27 12:58
 * @since jdk1.8
 */
@Slf4j
@Intercepts(@Signature(method = "query", type = Executor.class, args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class TestPlugin implements Interceptor {
    private Properties properties;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];
        Object paramter = args[1];
        String sqlid = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(paramter);
        String sql = boundSql.getSql();
        log.debug(sql);
        long start = System.currentTimeMillis();

        Object proceed = invocation.proceed();
        long end = System.currentTimeMillis();
        log.debug("耗時:" + (end - start) + "ms");
        return proceed;

    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

2、配置plugin
如下添加plugins標籤,並可配置輸入properties參數

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的主配置文件-->
<configuration>

    <!--自定義typeHandler-->
    <typeHandlers>
        <typeHandler handler="com.learn.zqw.handler.SexEnumTypeHandler"
                     javaType="com.learn.zqw.generator.domain.SexEnum"
                     jdbcType="SMALLINT"/>
    </typeHandlers>

    <plugins>
        <plugin interceptor="com.learn.zqw.plugin.TestPlugin">
            <property name="testKey" value="testVal"/>
        </plugin>
    </plugins>

    <!--配置環境-->
    <environments default="mysql">
        <!--配置mysql環境-->
        <environment id="mysql">
            <!--配置事務類型-->
            <transactionManager type="JDBC" />
            <!--配置數據源(連接池)-->
            <dataSource type="POOLED">
                <!--配置連接數據庫的4個基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_learn?useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>


    <!--指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件-->
    <mappers>

        <mapper resource="com/learn/zqw/IUserMapper.xml" />
        <mapper resource="com/learn/zqw/generator/mapper/StudentMapper.xml" />
        <mapper resource="com/learn/zqw/generator/mapper/BirdMapper.xml" />

        <!--可以直接把每個xml作配置,也可以使用包掃描,使用包掃描,如果使用純註解方式,也可以把對應的.xml文件刪除-->
        <!--<mapper resource="com/learn/zqw/sqlannotation/mapper/BookMapper.xml" />-->
        <!-- <mapper resource="com/learn/zqw/sqlannotation/mapper/LibraryMapper.xml" />-->
        <package name="com.learn.zqw.sqlannotation.mapper"/>
    </mappers>
    

</configuration>

3、測試

package com.learn.zqw.plugin;

import com.learn.zqw.generator.domain.Student;
import com.learn.zqw.generator.mapper.StudentMapper;
import lombok.Cleanup;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.io.IOException;
import java.io.InputStream;

/**
 * //TODO
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/6/27 14:05
 * @since jdk1.8
 */

@RunWith(JUnit4.class)
public class PluginTests {
    /**
     * 測試按照ID查詢
     * */
    @Test
    public void Test1() throws IOException {
        //1.讀取配置文件
        @Cleanup InputStream in = Resources.getResourceAsStream ("SqlMapConfig.xml");
        //2. 創建SqlSessionFactory
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        SqlSession session = factory.openSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        //按主鍵查詢
        Student student = mapper.selectByPrimaryKey(1);
        Assert.assertNotNull(student);
        System.out.println(student);
    }
}

執行後輸出了想要的日誌:

[2020/06/27 14:10:09,897] [DEBUG] [org.apache.ibatis.io.DefaultVFS:102] - Reader entry: <?xml version="1.0" encoding="UTF-8"?>
[2020/06/27 14:10:09,898] [DEBUG] [org.apache.ibatis.io.ResolverUtil:256] - Checking to see if class com.learn.zqw.sqlannotation.mapper.BookMapper matches criteria [is assignable to Object]
[2020/06/27 14:10:09,899] [DEBUG] [org.apache.ibatis.io.ResolverUtil:256] - Checking to see if class com.learn.zqw.sqlannotation.mapper.LibraryMapper matches criteria [is assignable to Object]
[2020/06/27 14:10:09,969] [DEBUG] [com.learn.zqw.plugin.TestPlugin:33] - select 
     
    id, name, real_name
   
    from student
    where id = ?
[2020/06/27 14:10:09,977] [DEBUG] [org.apache.ibatis.transaction.jdbc.JdbcTransaction:136] - Opening JDBC Connection
Sat Jun 27 14:10:10 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
[2020/06/27 14:10:10,220] [DEBUG] [org.apache.ibatis.datasource.pooled.PooledDataSource:424] - Created connection 370869802.
[2020/06/27 14:10:10,220] [DEBUG] [org.apache.ibatis.transaction.jdbc.JdbcTransaction:100] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@161b062a]
[2020/06/27 14:10:10,228] [DEBUG] [com.learn.zqw.generator.mapper.StudentMapper.selectByPrimaryKey:143] - ==>  Preparing: select id, name, real_name from student where id = ? 
[2020/06/27 14:10:10,254] [DEBUG] [com.learn.zqw.generator.mapper.StudentMapper.selectByPrimaryKey:143] - ==> Parameters: 1(Integer)
[2020/06/27 14:10:10,271] [DEBUG] [com.learn.zqw.generator.mapper.StudentMapper.selectByPrimaryKey:143] - <==      Total: 1
[2020/06/27 14:10:10,272] [DEBUG] [com.learn.zqw.plugin.TestPlugin:38] - 耗時:303ms
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章