Mybatis的插件开发
1 插件原理
- Mybatis在四大对象(Executor、ParameterHandler、ResultSetHandler、StatementHandler)创建的过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,从而实现在目标对象执行目标方法之前进行拦截的效果。
- Mybatis允许在已经映射语句指定过程中的某一点进行拦截调用。
2 插件开发步骤及应用示例
-
插件开发步骤:
- ①编写
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&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&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();
}
}