MyBatis插件开发与扩展:从原理到实战的完整指南
作为一名资深的Java开发者,我深知MyBatis在企业级应用中的重要地位。今天,我将带大家深入探索MyBatis的插件机制,从底层原理到实战应用,让你彻底掌握MyBatis的扩展能力!
文章目录
🔌 MyBatis插件机制深度解析
插件原理与执行流程
MyBatis插件机制基于JDK动态代理和责任链模式,通过拦截器(Interceptor)对核心组件进行增强。让我们先看看插件的执行流程:
// MyBatis插件执行流程示意
public class MyBatisPluginFlow {
// 1. 插件注册阶段
public void registerPlugin() {
// 在Configuration中注册插件
configuration.addInterceptor(new MyCustomInterceptor());
}
// 2. 代理对象创建阶段
public Object createProxy(Object target) {
// MyBatis会为四大核心对象创建代理
return Plugin.wrap(target, this);
}
// 3. 方法拦截执行阶段
public Object intercept(Invocation invocation) {
// 在这里执行自定义逻辑
Object result = invocation.proceed();
return result;
}
}
插件执行时序图:
- 配置加载 → 解析插件配置
- 对象创建 → 为目标对象创建代理
- 方法调用 → 触发拦截器链
- 逻辑执行 → 执行自定义增强逻辑
- 结果返回 → 返回处理后的结果
Interceptor接口详解
Interceptor
接口是MyBatis插件的核心,让我们深入了解其设计:
/**
* MyBatis拦截器接口实现
*/
@Intercepts({
@Signature(
type = Executor.class,
method = "update",
args = {MappedStatement.class, Object.class}
)
})
public class SqlExecutionTimeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
try {
// 执行原方法
Object result = invocation.proceed();
return result;
} finally {
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
// 记录SQL执行时间
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
System.out.println("SQL [" + ms.getId() + "] 执行耗时: " + executionTime + "ms");
}
}
@Override
public Object plugin(Object target) {
// 只对Executor进行代理
if (target instanceof Executor) {
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
// 设置插件属性
String threshold = properties.getProperty("threshold", "1000");
this.threshold = Long.parseLong(threshold);
}
private long threshold = 1000L;
}
关键注解说明:
@Intercepts
:声明拦截器@Signature
:指定拦截的方法签名type
:拦截的对象类型method
:拦截的方法名args
:方法参数类型
四大核心对象拦截
MyBatis提供了四个核心拦截点,每个都有其特定的应用场景:
1. Executor拦截器
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class ExecutorInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 可以在这里实现:
// - SQL执行监控
// - 慢查询记录
// - 数据权限控制
// - 缓存策略
String methodName = invocation.getMethod().getName();
if ("query".equals(methodName)) {
// 查询拦截逻辑
return handleQuery(invocation);
} else if ("update".equals(methodName)) {
// 更新拦截逻辑
return handleUpdate(invocation);
}
return invocation.proceed();
}
private Object handleQuery(Invocation invocation) throws Throwable {
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
// 添加数据权限过滤
if (needDataPermissionFilter(ms.getId())) {
parameter = addDataPermissionCondition(parameter);
invocation.getArgs()[1] = parameter;
}
return invocation.proceed();
}
private Object handleUpdate(Invocation invocation) throws Throwable {
// 自动填充创建时间、修改时间等
Object parameter = invocation.getArgs()[1];
autoFillAuditFields(parameter);
return invocation.proceed();
}
}
2. StatementHandler拦截器
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class StatementHandlerInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
// 获取SQL语句
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
// SQL重写示例:自动添加租户隔离条件
if (needTenantIsolation(sql)) {
String newSql = addTenantCondition(sql);
// 通过反射修改SQL
Field sqlField = boundSql.getClass().getDeclaredField("sql");
sqlField.setAccessible(true);
sqlField.set(boundSql, newSql);
}
return invocation.proceed();
}
private boolean needTenantIsolation(String sql) {
// 判断是否需要租户隔离
return sql.toLowerCase().contains("select") &&
!sql.toLowerCase().contains("tenant_id");
}
private String addTenantCondition(String sql) {
// 添加租户条件
String tenantId = getCurrentTenantId();
return sql + " AND tenant_id = '" + tenantId + "'";
}
}
3. ParameterHandler拦截器
@Intercepts({
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
public class ParameterHandlerInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
// 获取参数对象
Object parameterObject = parameterHandler.getParameterObject();
// 参数加密处理
if (parameterObject != null) {
encryptSensitiveFields(parameterObject);
}
return invocation.proceed();
}
private void encryptSensitiveFields(Object parameter) {
// 使用反射处理敏感字段加密
Field[] fields = parameter.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Sensitive.class)) {
field.setAccessible(true);
try {
Object value = field.get(parameter);
if (value instanceof String) {
String encryptedValue = encrypt((String) value);
field.set(parameter, encryptedValue);
}
} catch (IllegalAccessException e) {
// 处理异常
}
}
}
}
}
4. ResultSetHandler拦截器
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class ResultSetHandlerInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 执行原方法获取结果
Object result = invocation.proceed();
// 结果集后处理
if (result instanceof List) {
List<?> list = (List<?>) result;
for (Object item : list) {
// 敏感数据脱敏
desensitizeData(item);
// 数据权限过滤
filterByDataPermission(item);
}
}
return result;
}
private void desensitizeData(Object item) {
// 实现数据脱敏逻辑
Field[] fields = item.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Desensitize.class)) {
field.setAccessible(true);
try {
Object value = field.get(item);
if (value instanceof String) {
String maskedValue = maskSensitiveData((String) value);
field.set(item, maskedValue);
}
} catch (IllegalAccessException e) {
// 处理异常
}
}
}
}
}
插件开发实战案例
让我们开发一个完整的SQL审计插件:
/**
* SQL审计插件 - 记录所有SQL执行情况
*/
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Component
public class SqlAuditInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(SqlAuditInterceptor.class);
@Autowired
private SqlAuditService sqlAuditService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
String sqlId = null;
String sql = null;
Object parameter = null;
try {
// 获取SQL信息
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
sqlId = ms.getId();
parameter = invocation.getArgs()[1];
// 获取实际执行的SQL
BoundSql boundSql = ms.getBoundSql(parameter);
sql = boundSql.getSql();
// 执行原方法
Object result = invocation.proceed();
// 记录成功执行的SQL
long executionTime = System.currentTimeMillis() - startTime;
recordSqlExecution(sqlId, sql, parameter, executionTime, true, null, result);
return result;
} catch (Exception e) {
// 记录执行失败的SQL
long executionTime = System.currentTimeMillis() - startTime;
recordSqlExecution(sqlId, sql, parameter, executionTime, false, e.getMessage(), null);
throw e;
}
}
private void recordSqlExecution(String sqlId, String sql, Object parameter,
long executionTime, boolean success,
String errorMessage, Object result) {
try {
SqlAuditRecord record = new SqlAuditRecord();
record.setSqlId(sqlId);
record.setSql(formatSql(sql));
record.setParameter(JSON.toJSONString(parameter));
record.setExecutionTime(executionTime);
record.setSuccess(success);
record.setErrorMessage(errorMessage);
record.setExecuteTime(new Date());
record.setUserId(getCurrentUserId());
record.setUserName(getCurrentUserName());
record.setIpAddress(getCurrentIpAddress());
// 异步记录审计日志
sqlAuditService.recordAsync(record);
// 慢查询告警
if (executionTime > getSlowQueryThreshold()) {
alertSlowQuery(record);
}
} catch (Exception e) {
logger.error("记录SQL审计日志失败", e);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 设置慢查询阈值
String threshold = properties.getProperty("slowQueryThreshold", "3000");
this.slowQueryThreshold = Long.parseLong(threshold);
}
private long slowQueryThreshold = 3000L;
}
🛠️ 常用插件与工具实战
PageHelper分页插件
PageHelper是MyBatis生态中最受欢迎的分页插件:
<!-- Maven依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
# application.yml配置
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
page-size-zero: true
/**
* PageHelper使用示例
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 分页查询用户
*/
public PageInfo<User> findUsersByPage(int pageNum, int pageSize, String keyword) {
// 开启分页
PageHelper.startPage(pageNum, pageSize);
// 执行查询
List<User> users = userMapper.findUsersByKeyword(keyword);
// 封装分页信息
return new PageInfo<>(users);
}
/**
* 使用Lambda方式进行分页
*/
public PageInfo<User> findUsersWithLambda(int pageNum, int pageSize) {
return PageHelper.startPage(pageNum, pageSize)
.doSelectPageInfo(() -> userMapper.selectAll());
}
/**
* 自定义分页查询
*/
public PageInfo<UserVO> findUserVOsByPage(UserQueryDTO queryDTO) {
PageHelper.startPage(queryDTO.getPageNum(), queryDTO.getPageSize());
// 复杂查询
List<UserVO> userVOs = userMapper.findUserVOsWithConditions(queryDTO);
PageInfo<UserVO> pageInfo = new PageInfo<>(userVOs);
// 设置额外信息
pageInfo.setTotal(pageInfo.getTotal());
return pageInfo;
}
}
PageHelper高级特性:
/**
* PageHelper高级用法
*/
@RestController
public class UserController {
/**
* 支持排序的分页查询
*/
@GetMapping("/users")
public Result<PageInfo<User>> getUsers(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String orderBy) {
// 设置排序
if (StringUtils.isNotBlank(orderBy)) {
PageHelper.startPage(pageNum, pageSize, orderBy);
} else {
PageHelper.startPage(pageNum, pageSize);
}
List<User> users = userService.findAllUsers();
PageInfo<User> pageInfo = new PageInfo<>(users);
return Result.success(pageInfo);
}
/**
* 分页查询并统计
*/
@GetMapping("/users/stats")
public Result<UserPageStats> getUsersWithStats(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
// 分页查询
PageHelper.startPage(pageNum, pageSize);
List<User> users = userService.findAllUsers();
PageInfo<User> pageInfo = new PageInfo<>(users);
// 统计信息
UserStats stats = userService.getUserStats();
UserPageStats result = new UserPageStats();
result.setPageInfo(pageInfo);
result.setStats(stats);
return Result.success(result);
}
}
通用Mapper插件
通用Mapper提供了单表的CRUD操作:
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>4.2.1</version>
</dependency>
/**
* 通用Mapper使用示例
*/
@Table(name = "sys_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username")
private String username;
@Column(name = "email")
private String email;
@Column(name = "create_time")
private Date createTime;
// getter/setter省略
}
/**
* 继承通用Mapper接口
*/
public interface UserMapper extends Mapper<User>, MySqlMapper<User> {
// 自动拥有基础CRUD方法
// selectByPrimaryKey、selectAll、insert、updateByPrimaryKey等
// 可以添加自定义方法
List<User> findByUsername(String username);
}
/**
* 服务层使用
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 条件查询示例
*/
public List<User> findUsersByCondition(String username, String email) {
Example example = new Example(User.class);
Example.Criteria criteria = example.createCriteria();
if (StringUtils.isNotBlank(username)) {
criteria.andLike("username", "%" + username + "%");
}
if (StringUtils.isNotBlank(email)) {
criteria.andEqualTo("email", email);
}
example.setOrderByClause("create_time desc");
return userMapper.selectByExample(example);
}
/**
* 批量操作示例
*/
@Transactional
public void batchInsertUsers(List<User> users) {
for (User user : users) {
user.setCreateTime(new Date());
userMapper.insertSelective(user);
}
}
/**
* 动态更新示例
*/
public int updateUserSelective(User user) {
return userMapper.updateByPrimaryKeySelective(user);
}
}
MyBatis-Plus增强工具
MyBatis-Plus是MyBatis的增强工具,提供了更强大的功能:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
/**
* MyBatis-Plus实体类
*/
@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableLogic
private Integer deleted;
@Version
private Integer version;
// getter/setter省略
}
/**
* 继承BaseMapper
*/
public interface UserMapper extends BaseMapper<User> {
// 自动拥有强大的CRUD功能
}
/**
* 服务层继承ServiceImpl
*/
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
/**
* 条件构造器查询
*/
public List<User> findActiveUsers(String keyword) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
.or()
.like(StringUtils.isNotBlank(keyword), User::getEmail, keyword)
.eq(User::getDeleted, 0)
.orderByDesc(User::getCreateTime);
return list(wrapper);
}
/**
* 分页查询
*/
public IPage<User> findUsersByPage(Page<User> page, String keyword) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
.eq(User::getDeleted, 0);
return page(page, wrapper);
}
/**
* 批量更新
*/
@Transactional
public boolean batchUpdateStatus(List<Long> ids, Integer status) {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.in(User::getId, ids)
.set(User::getStatus, status);
return update(wrapper);
}
}
MyBatis-Plus配置类:
@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防全表更新与删除插件
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
/**
* 自动填充处理器
*/
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
};
}
}
代码生成器使用
MyBatis-Plus代码生成器:
/**
* MyBatis-Plus代码生成器
*/
public class CodeGenerator {
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("your-name");
gc.setOpen(false);
gc.setServiceName("%sService");
gc.setBaseResultMap(true);
gc.setBaseColumnList(true);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("password");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("system");
pc.setParent("com.example");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// 自定义属性注入
Map<String, Object> map = new HashMap<>();
map.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
this.setMap(map);
}
};
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
@Override
public String outputFile(TableInfo tableInfo) {
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude("sys_user", "sys_role"); // 需要生成的表名
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix("sys_"); // 表前缀
mpg.setStrategy(strategy);
// 模板引擎配置
mpg.setTemplateEngine(new VelocityTemplateEngine());
// 执行生成
mpg.execute();
}
}
自定义代码生成器模板:
/**
* 自定义代码生成器
*/
@Component
public class CustomCodeGenerator {
/**
* 生成完整的CRUD代码
*/
public void generateCrudCode(String tableName, String entityName) {
// 生成Entity
generateEntity(tableName, entityName);
// 生成Mapper
generateMapper(entityName);
// 生成Service
generateService(entityName);
// 生成Controller
generateController(entityName);
// 生成前端页面
generateVuePage(entityName);
}
private void generateEntity(String tableName, String entityName) {
// 使用Freemarker模板生成Entity类
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("tableName", tableName);
dataModel.put("entityName", entityName);
dataModel.put("fields", getTableFields(tableName));
generateFromTemplate("entity.ftl", dataModel,
"src/main/java/com/example/entity/" + entityName + ".java");
}
private void generateMapper(String entityName) {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("entityName", entityName);
// 生成Mapper接口
generateFromTemplate("mapper.ftl", dataModel,
"src/main/java/com/example/mapper/" + entityName + "Mapper.java");
// 生成Mapper XML
generateFromTemplate("mapper-xml.ftl", dataModel,
"src/main/resources/mapper/" + entityName + "Mapper.xml");
}
private void generateService(String entityName) {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("entityName", entityName);
// 生成Service接口
generateFromTemplate("service.ftl", dataModel,
"src/main/java/com/example/service/" + entityName + "Service.java");
// 生成Service实现
generateFromTemplate("service-impl.ftl", dataModel,
"src/main/java/com/example/service/impl/" + entityName + "ServiceImpl.java");
}
private void generateController(String entityName) {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("entityName", entityName);
generateFromTemplate("controller.ftl", dataModel,
"src/main/java/com/example/controller/" + entityName + "Controller.java");
}
}
🚀 插件开发最佳实践
1. 性能优化建议
/**
* 高性能插件开发要点
*/
@Intercepts({@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class PerformanceOptimizedInterceptor implements Interceptor {
// 使用ThreadLocal避免线程安全问题
private static final ThreadLocal<Long> START_TIME = new ThreadLocal<>();
// 使用缓存避免重复计算
private final Map<String, Boolean> sqlIdCache = new ConcurrentHashMap<>();
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
String sqlId = ms.getId();
// 快速判断是否需要处理
if (!needIntercept(sqlId)) {
return invocation.proceed();
}
START_TIME.set(System.currentTimeMillis());
try {
return invocation.proceed();
} finally {
long executionTime = System.currentTimeMillis() - START_TIME.get();
START_TIME.remove(); // 防止内存泄漏
// 异步处理,避免影响主流程
processAsync(sqlId, executionTime);
}
}
private boolean needIntercept(String sqlId) {
return sqlIdCache.computeIfAbsent(sqlId, this::shouldIntercept);
}
private void processAsync(String sqlId, long executionTime) {
CompletableFuture.runAsync(() -> {
// 异步处理逻辑
handleSlowQuery(sqlId, executionTime);
});
}
}
2. 插件链管理
/**
* 插件链管理器
*/
@Configuration
public class InterceptorChainManager {
@Bean
@Order(1)
public SqlAuditInterceptor sqlAuditInterceptor() {
return new SqlAuditInterceptor();
}
@Bean
@Order(2)
public DataPermissionInterceptor dataPermissionInterceptor() {
return new DataPermissionInterceptor();
}
@Bean
@Order(3)
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
return new PerformanceMonitorInterceptor();
}
/**
* 动态插件管理
*/
@Bean
public DynamicInterceptorManager dynamicInterceptorManager() {
return new DynamicInterceptorManager();
}
}
/**
* 动态插件管理器
*/
public class DynamicInterceptorManager {
private final List<Interceptor> interceptors = new CopyOnWriteArrayList<>();
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public void removeInterceptor(Class<? extends Interceptor> interceptorClass) {
interceptors.removeIf(interceptor ->
interceptor.getClass().equals(interceptorClass));
}
public void enableInterceptor(Class<? extends Interceptor> interceptorClass) {
// 启用指定插件
}
public void disableInterceptor(Class<? extends Interceptor> interceptorClass) {
// 禁用指定插件
}
}
📊 总结与展望
MyBatis插件机制为我们提供了强大的扩展能力,通过合理使用插件,我们可以:
- 提升开发效率:通过代码生成器和通用Mapper减少重复代码
- 增强系统功能:实现数据权限、审计日志、性能监控等企业级功能
- 优化系统性能:通过缓存、分页、批量操作等提升系统性能
- 保证数据安全:通过加密、脱敏、权限控制保护敏感数据
希望这篇文章能帮助你深入理解MyBatis插件机制,在实际项目中灵活运用这些强大的扩展功能!
如果觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!有任何问题也欢迎在评论区讨论交流! 🚀