mybatis的插件機制示例詳解
前言
Mybatis作為一個應(yīng)用廣泛的優(yōu)秀的ORM框架,已經(jīng)成了JavaWeb世界近乎標(biāo)配的部分,這個框架具有強大的靈活性,在四大組件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)處提供了簡單易用的插件擴展機制。Mybatis對持久層的操作就是借助于四大核心對象。MyBatis支持用插件對四大核心對象進行攔截,對mybatis來說插件就是攔截器,用來增強核心對象的功能,增強功能本質(zhì)上是借助于底層的動態(tài)代理實現(xiàn)的,換句話說,MyBatis中的四大對象都是代理對象。
四大核心對象簡介
MyBatis 四大核心對象
ParameterHandler:處理SQL的參數(shù)對象
ResultSetHandler:處理SQL的返回結(jié)果集
StatementHandler:數(shù)據(jù)庫的處理對象,用于執(zhí)行SQL語句
Executor:MyBatis的執(zhí)行器,用于執(zhí)行增刪改查操作
Mybatis插件原理
- Mybatis的插件借助于責(zé)任鏈的模式進行對攔截的處理
- 使用動態(tài)代理對目標(biāo)對象進行包裝,達到攔截的目的
- 作用于Mybatis的作用域?qū)ο笾?/li>
攔截
插件具體是如何攔截并附加額外的功能的呢?
以ParameterHandler 來說
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object object, BoundSql sql, InterceptorChain interceptorChain){
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,object,sql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
interceptorChain 保存了所有的攔截器(interceptors),是mybatis初始化的時候創(chuàng)建的。調(diào)用攔截器鏈中的攔截器依次的對目標(biāo)進行攔截或增強。interceptor.plugin(target)中的target就可以理解為mybatis中的四大對象。返回的target是被重重代理后的對象。
插件接口
Mybatis插件接口-Interceptor
1.Intercept方法,插件的核心方法
2.plugin方法,生成target的代理對象
3.setProperties方法,傳遞插件所需參數(shù)
插件實例
插件開發(fā)需要以下步驟
- 自定義插件需要實現(xiàn)上述接口
- 增加@Intercepts注解(聲明是哪個核心組件的插件,以及對哪些方法進行擴展)
- 在xml文件中配置插件
/** 插件簽名,告訴mybatis單錢插件用來攔截那個對象的哪個方法 **/
@Intercepts({@Signature(type = ResultSetHandler.class,method ="handleResultSets",args = Statement.class)})
public class MyFirstInterceptor implements Interceptor {
/** @Description 攔截目標(biāo)對象的目標(biāo)方法 **/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("攔截的目標(biāo)對象:"+invocation.getTarget());
Object object = invocation.proceed();
return object;
}
/**
* @Description 包裝目標(biāo)對象 為目標(biāo)對象創(chuàng)建代理對象
* @Param target為要攔截的對象
* @Return 代理對象
*/
@Override
public Object plugin(Object target) {
System.out.println("將要包裝的目標(biāo)對象:"+target);
return Plugin.wrap(target,this);
}
/** 獲取配置文件的屬性 **/
@Override
public void setProperties(Properties properties) {
System.out.println("插件配置的初始化參數(shù):"+properties);
}
}
在mybatis.xml中配置插件
<!-- 自定義插件 --> <plugins> <plugin interceptor="mybatis.interceptor.MyFirstInterceptor"> <!--配置參數(shù)--> <property name="name" value="Bob"/> </plugin> </plugins>
調(diào)用查詢方法,查詢方法會返回ResultSet
public class MyBatisTest {
public static SqlSessionFactory sqlSessionFactory = null;
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
String resource = "mybatis-config.xml";
try {
Reader reader = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
return sqlSessionFactory;
}
public void testGetById()
{
SqlSession sqlSession = this.getSqlSessionFactory().openSession();
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
Person person=personMapper.getById(2001);
System.out.println(person.toString());
}
public static void main(String[] args) {
new MyBatisTest().testGetById();
}
}
輸出結(jié)果
插件配置的初始化參數(shù):{name=Bob}
將要包裝的目標(biāo)對象:org.apache.ibatis.executor.CachingExecutor@754ba872
將要包裝的目標(biāo)對象:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@192b07fd
將要包裝的目標(biāo)對象:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@7e0b0338
將要包裝的目標(biāo)對象:org.apache.ibatis.executor.statement.RoutingStatementHandler@1e127982
攔截的目標(biāo)對象:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@7e0b0338
Person{id=2001, username='Tom', email='email@0', gender='F'}
多插件開發(fā)過程
1.創(chuàng)建代理對象時,按照插件配置的順序進行包裝
2.執(zhí)行目標(biāo)方法后,是按照代理的逆向進行執(zhí)行
總結(jié)
1.遵循插件盡量不使用的原則,因為會修改底層設(shè)計
2.插件是生成的層層代理對象的責(zé)任鏈模式,使用反射機制實現(xiàn)
3.插件的編寫要考慮全面,特別是多個插件層層代理的時候
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。
相關(guān)文章
SpringBoot 配合 SpringSecurity 實現(xiàn)自動登錄功能的代碼
這篇文章主要介紹了SpringBoot 配合 SpringSecurity 實現(xiàn)自動登錄功能的代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
java 中Object與Objects的區(qū)別在哪里
這篇文章主要介紹了java 中Object與Objects的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05
Eclipse轉(zhuǎn)Itellij IDEA導(dǎo)入Git/svn本地項目的詳細步驟
這篇文章主要介紹了Eclipse轉(zhuǎn)Itellij IDEA導(dǎo)入Git/svn本地項目,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
使用mybatisPlus的queryWrapper做左聯(lián)接,內(nèi)聯(lián)接方式
本文介紹了如何使用Mybatis-Plus的QueryWrapper進行SQL查詢,包括左連接、內(nèi)連接等操作,通過示例代碼展示了如何構(gòu)建復(fù)雜的SQL查詢,并將結(jié)果存儲在List對象中返回,希望給讀者提供參考2025-03-03
rabbitmq的消息持久化處理開啟,再關(guān)閉后,消費者啟動報錯問題
這篇文章主要介紹了rabbitmq的消息持久化處理開啟,再關(guān)閉后,消費者啟動報錯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Java Web開發(fā)入門書籍實例解析(總結(jié)一)
從事Java Web開發(fā)這一段時間來,對Java 面向?qū)ο蟮乃枷牒蚆VC開發(fā)模式可以說已經(jīng)熟悉了。我當(dāng)前參與的項目使用的框架是Spring、SpringMVC、Hibernate。下面腳本之家小編給大家整理一篇教程幫助大家學(xué)習(xí)javaweb相關(guān)知識,感興趣的朋友可以參考下2016-03-03

