1. 程式人生 > 實用技巧 >Mybatis的外掛開發

Mybatis的外掛開發

外掛原理

  • Mybatis在四大物件(Executor、ParameterHandler、ResultSetHandler、StatementHandler)建立的過程中,都會有外掛進行介入。外掛可以利用動態代理機制一層層的包裝目標物件,從而實現在目標物件執行目標方法之前進行攔截的效果。
  • Mybatis允許在已經對映語句指定過程中的某一點進行攔截呼叫。

外掛開發步驟及應用示例

  • 外掛開發步驟:

    • ①編寫Interceptor的實現類。
    • ②使用@Intercepts註解完成外掛簽名。
    • ③在全域性配置檔案中註冊外掛。
  • 示例:

  • sql指令碼:

DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `last_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  • 匯入相關jar包的Maven座標:
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
  • log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug" />
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info" />
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>
  • Employee.java
package com.sunxiaping.domain;

public class Employee {
    private Integer id;

    private String lastName;

    private String email;

    private String gender;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}
  • EmployeeMapper.java
package com.sunxiaping.mapper;

import com.sunxiaping.domain.Employee;

public interface EmployeeMapper {

    Employee findById(Integer id);

}
  • MyInterceptor.java
package com.sunxiaping.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Statement;
import java.util.Properties;

//定義攔截那個物件的那個方法的那個引數
@Intercepts({@Signature(type = StatementHandler.class, method = "parameterize", args = Statement.class)})
public class MyInterceptor implements Interceptor {

    /**
     * 攔截目標物件的目標方法的執行
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    public Object intercept(Invocation invocation) throws Throwable {

        System.out.println("--------MyInterceptor.intercept------------"+invocation.getMethod());
        //執行目標方法
        Object proceed = invocation.proceed();
        return proceed;
    }

    /**
     * 包裝目標物件:為目標物件建立一個代理物件
     *
     * @param target
     * @return
     */
    public Object plugin(Object target) {

        System.out.println("------MyInterceptor--plugin-------"+target);

        //藉助Plugin的wrap使用當前的攔截器包裝目標物件
        Object wrap = Plugin.wrap(target, this);
        //為當前target建立的動態代理
        return wrap;
    }

    /**
     * 將外掛註冊時的properties屬性設定進來
     *
     * @param properties
     */
    public void setProperties(Properties properties) {
        System.out.println("外掛配置的資訊 = " + properties);
    }
}
  • mybatis-config.xml
<?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">
<configuration>
    <!-- 註冊外掛 -->
    <plugins>
        <plugin interceptor="com.sunxiaping.plugin.MyInterceptor">
            <property name="username" value="xuweiwei"/>
            <property name="password" value="123456"/>
        </plugin>
    </plugins>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.64.100:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/sunxiaping/mapper/EmployeeMapper.xml"/>
    </mappers>
</configuration>
  • 測試:
package com.sunxiaping;

import com.sunxiaping.domain.Employee;
import com.sunxiaping.mapper.EmployeeMapper;
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 java.io.IOException;
import java.io.InputStream;

public class EmployeeTest {
    
    public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = employeeMapper.findById(1);
        System.out.println("employee = " + employee);

        sqlSession.close();
    }
}