第一章:插件原理

  • Mybatis 在四大对象( Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler )创建的过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,从而实现在目标对象执行目标方法之前进行拦截的效果。
  • Mybatis 允许在已经映射语句指定过程中的某一点进行拦截调用。

第二章:插件开发步骤及应用示例

  • 插件开发步骤:

    • ① 编写 Interceptor 的实现类。
    • ② 使用 @Intercepts 注解完成插件签名。
    • ③ 在全局配置文件中注册插件。
  • 示例:

  • sql 脚本:
  1. DROP TABLE IF EXISTS `employee`;
  2. CREATE TABLE `employee` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `last_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  5. `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  6. `gender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  7. PRIMARY KEY (`id`) USING BTREE
  8. ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  • 导入相关 jar 包的 Maven 坐标:
  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.5.5</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>log4j</groupId>
  8. <artifactId>log4j</artifactId>
  9. <version>1.2.17</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>mysql</groupId>
  13. <artifactId>mysql-connector-java</artifactId>
  14. <version>8.0.21</version>
  15. </dependency>
  • log4j.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
  3. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  4. <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
  5. <param name="Encoding" value="UTF-8" />
  6. <layout class="org.apache.log4j.PatternLayout">
  7. <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
  8. </layout>
  9. </appender>
  10. <logger name="java.sql">
  11. <level value="debug" />
  12. </logger>
  13. <logger name="org.apache.ibatis">
  14. <level value="info" />
  15. </logger>
  16. <root>
  17. <level value="debug" />
  18. <appender-ref ref="STDOUT" />
  19. </root>
  20. </log4j:configuration>
  • Employee.java
  1. package com.sunxiaping.domain;
  2. public class Employee {
  3. private Integer id;
  4. private String lastName;
  5. private String email;
  6. private String gender;
  7. public Integer getId() {
  8. return id;
  9. }
  10. public void setId(Integer id) {
  11. this.id = id;
  12. }
  13. public String getLastName() {
  14. return lastName;
  15. }
  16. public void setLastName(String lastName) {
  17. this.lastName = lastName;
  18. }
  19. public String getEmail() {
  20. return email;
  21. }
  22. public void setEmail(String email) {
  23. this.email = email;
  24. }
  25. public String getGender() {
  26. return gender;
  27. }
  28. public void setGender(String gender) {
  29. this.gender = gender;
  30. }
  31. @Override
  32. public String toString() {
  33. return "Employee{" +
  34. "id=" + id +
  35. ", lastName='" + lastName + '\'' +
  36. ", email='" + email + '\'' +
  37. ", gender='" + gender + '\'' +
  38. '}';
  39. }
  40. }
  • EmployeeMapper.java
  1. package com.sunxiaping.mapper;
  2. import com.sunxiaping.domain.Employee;
  3. public interface EmployeeMapper {
  4. Employee findById(Integer id);
  5. }
  • MyInterceptor.java
  1. package com.sunxiaping.plugin;
  2. import org.apache.ibatis.executor.statement.StatementHandler;
  3. import org.apache.ibatis.plugin.*;
  4. import java.sql.Statement;
  5. import java.util.Properties;
  6. //定义拦截那个对象的那个方法的那个参数
  7. @Intercepts({@Signature(type = StatementHandler.class, method = "parameterize", args = Statement.class)})
  8. public class MyInterceptor implements Interceptor {
  9. /**
  10. * 拦截目标对象的目标方法的执行
  11. *
  12. * @param invocation
  13. * @return
  14. * @throws Throwable
  15. */
  16. public Object intercept(Invocation invocation) throws Throwable {
  17. System.out.println("--------MyInterceptor.intercept------------"+invocation.getMethod());
  18. //执行目标方法
  19. Object proceed = invocation.proceed();
  20. return proceed;
  21. }
  22. /**
  23. * 包装目标对象:为目标对象创建一个代理对象
  24. *
  25. * @param target
  26. * @return
  27. */
  28. public Object plugin(Object target) {
  29. System.out.println("------MyInterceptor--plugin-------"+target);
  30. //借助Plugin的wrap使用当前的拦截器包装目标对象
  31. Object wrap = Plugin.wrap(target, this);
  32. //为当前target创建的动态代理
  33. return wrap;
  34. }
  35. /**
  36. * 将插件注册时的properties属性设置进来
  37. *
  38. * @param properties
  39. */
  40. public void setProperties(Properties properties) {
  41. System.out.println("插件配置的信息 = " + properties);
  42. }
  43. }
  • mybatis-config.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- 注册插件 -->
  7. <plugins>
  8. <plugin interceptor="com.sunxiaping.plugin.MyInterceptor">
  9. <property name="username" value="xuweiwei"/>
  10. <property name="password" value="123456"/>
  11. </plugin>
  12. </plugins>
  13. <environments default="development">
  14. <environment id="development">
  15. <transactionManager type="JDBC"/>
  16. <dataSource type="POOLED">
  17. <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
  18. <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"/>
  19. <property name="username" value="root"/>
  20. <property name="password" value="123456"/>
  21. </dataSource>
  22. </environment>
  23. </environments>
  24. <mappers>
  25. <mapper resource="com/sunxiaping/mapper/EmployeeMapper.xml"/>
  26. </mappers>
  27. </configuration>
  • 测试:
  1. package com.sunxiaping;
  2. import com.sunxiaping.domain.Employee;
  3. import com.sunxiaping.mapper.EmployeeMapper;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. public class EmployeeTest {
  11. public static void main(String[] args) throws IOException {
  12. String resource = "mybatis-config.xml";
  13. InputStream inputStream = Resources.getResourceAsStream(resource);
  14. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  15. SqlSession sqlSession = sqlSessionFactory.openSession();
  16. EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
  17. Employee employee = employeeMapper.findById(1);
  18. System.out.println("employee = " + employee);
  19. sqlSession.close();
  20. }
  21. }