1畸陡、前言
簡單的說吓懈,mybatis插件就是對ParameterHandler、ResultSetHandler季希、StatementHandler、Executor這四個接口上的方法進行攔截,利用JDK動態(tài)代理機制饰恕,為這些接口的實現(xiàn)類創(chuàng)建代理對象甘穿,在執(zhí)行方法時,先去執(zhí)行代理對象的方法峰尝,從而執(zhí)行自己編寫的攔截邏輯,所以真正要用好mybatis插件收恢,主要還是要熟悉這四個接口的方法以及這些方法上的參數(shù)的含義武学;
另外,如果配置了多個攔截器的話伦意,會出現(xiàn)層層代理的情況火窒,即代理對象代理了另外一個代理對象,形成一個代理鏈條驮肉,執(zhí)行的時候熏矿,也是層層執(zhí)行;
關(guān)于mybatis插件涉及到的設(shè)計模式和軟件思想如下:
設(shè)計模式:代理模式离钝、責任鏈模式票编;
軟件思想:AOP編程思想,降低模塊間的耦合度卵渴,使業(yè)務(wù)模塊更加獨立慧域;
一些注意事項:
不要定義過多的插件,代理嵌套過多浪读,執(zhí)行方法的時候吊趾,比較耗性能宛裕;
攔截器實現(xiàn)類的intercept方法里最后不要忘了執(zhí)行invocation.proceed()方法,否則多個攔截器情況下论泛,執(zhí)行鏈條會斷掉揩尸;
2、Springboot 編寫 mybatis 插件
編寫 mybatis 插件很簡單屁奏,首先定義要攔截的是上面說到的哪個類岩榆,攔截哪個方法,參數(shù)是啥坟瓢,然后配置一下即可
package com.snowflake1.test.config;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.util.Properties;
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {
private Logger logger = LoggerFactory.getLogger(MyPlugin.class);
private long time;
//方法攔截
@Override
public Object intercept(Invocation invocation) throws Throwable {
//通過StatementHandler獲取執(zhí)行的sql
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
long start = System.currentTimeMillis();
Object proceed = invocation.proceed();
long end = System.currentTimeMillis();
if ((end - start) > time) {
logger.info("本次數(shù)據(jù)庫操作是慢查詢勇边,sql是:" + sql);
}
return proceed;
}
//獲取到攔截的對象,底層也是通過代理實現(xiàn)的折联,實際上是拿到一個目標代理對象
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
//獲取設(shè)置的閾值等參數(shù)
@Override
public void setProperties(Properties properties) {
this.time = Long.parseLong(properties.getProperty("time"));
}
}
在 springboot 那配置一下(我用的是 mybatisplus)
package com.snowflake1.test.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class MapperConfig {
//將插件加入到mybatis插件攔截鏈中
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(MybatisConfiguration configuration) {
//插件攔截鏈采用了責任鏈模式粒褒,執(zhí)行順序和加入連接鏈的順序有關(guān)
MyPlugin myPlugin = new MyPlugin();
//設(shè)置參數(shù),比如閾值等诚镰,可以在配置文件中配置奕坟,這里直接寫死便于測試
Properties properties = new Properties();
//這里設(shè)置慢查詢閾值為1毫秒,便于測試
properties.setProperty("time", "1");
myPlugin.setProperties(properties);
configuration.addInterceptor(myPlugin);
}
};
}
}