深入淺出Mybatis原始碼系列(六)---objectFactory、plugins、mappers簡介與配置
上篇文章《深入淺出Mybatis原始碼系列(五)---TypeHandler簡介及配置(mybatis原始碼篇)》簡單看了一下TypeHandler, 本次將結束對於mybatis的配置檔案的學習, 本次涉及到剩下沒提及到的幾個節點的配置:objectFactory、databaseIdProvider、plugins、mappers。
那麼,接下來,就簡單介紹一下這幾個配置的作用吧:
1、objectFactory是幹什麼的? 需要配置嗎?
MyBatis 每次建立結果物件的新例項時,它都會使用一個物件工廠(ObjectFactory)例項來完成。預設的物件工廠需要做的僅僅是例項化目標類,要麼通過預設構造方法,要麼在引數對映存在的時候通過引數構造方法來例項化。預設情況下,我們不需要配置,mybatis會呼叫預設實現的objectFactory。 除非我們要自定義ObjectFactory的實現, 那麼我們才需要去手動配置。
那麼怎麼自定義實現ObjectFactory? 怎麼配置呢?
自定義ObjectFactory只需要去繼承DefaultObjectFactory(是ObjectFactory介面的實現類),並重寫其方法即可。具體的,本處不多說,後面再具體講解。
寫好了ObjectFactory, 僅需做如下配置:
<configuration> ...... <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory> ...... </configuration
2、plugin有何作用? 需要配置嗎?
plugins 是一個可選配置。mybatis中的plugin其實就是個interceptor, 它可以攔截Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler 的部分方法,處理我們自己的邏輯。Executor就是真正執行sql語句的東西, ParameterHandler 是處理我們傳入引數的,還記得前面講TypeHandler的時候提到過,mybatis預設幫我們實現了不少的typeHandler, 當我們不顯示配置typeHandler的時候,mybatis會根據引數型別自動選擇合適的typeHandler執行,其實就是ParameterHandler 在選擇。ResultSetHandler 就是處理返回結果的。
怎麼自定義plugin ? 怎麼配置?
要自定義一個plugin, 需要去實現Interceptor介面, 這兒不細說, 後面實戰部分會詳細講解。定義好之後,配置如下:
<configuration>
......
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
......
</configuration>
3、mappers, 這下引出mybatis的核心之一了,mappers作用 ? 需要配置嗎?
mappers 節點下,配置我們的mapper對映檔案, 所謂的mapper對映檔案,就是讓mybatis 用來建立資料表和javabean對映的一個橋樑。在我們實際開發中,通常一個mapper檔案對應一個dao介面, 這個mapper可以看做是dao的實現。所以,mappers必須配置。
那麼怎麼配置呢?
<configuration>
......
<mappers>
<!-- 第一種方式:通過resource指定 -->
<mapper resource="com/dy/dao/userDao.xml"/>
<!-- 第二種方式, 通過class指定介面,進而將介面與對應的xml檔案形成對映關係
不過,使用這種方式必須保證 介面與mapper檔案同名(不區分大小寫),
我這兒介面是UserDao,那麼意味著mapper檔案為UserDao.xml
<mapper class="com.dy.dao.UserDao"/>
-->
<!-- 第三種方式,直接指定包,自動掃描,與方法二同理
<package name="com.dy.dao"/>
-->
<!-- 第四種方式:通過url指定mapper檔案位置
<mapper url="file://........"/>
-->
</mappers>
......
</configuration>
本篇僅作簡單介紹, 更高階的使用以及其實現原理,會在後面的實戰部分進行詳細講解。
這幾個節點的解析原始碼,與之前提到的那些節點的解析類似,故此處不再講。 我將原始碼貼在這裡, 需要的可以開啟看看。
/**
* objectFactory 節點解析
*/
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
//讀取type屬性的值, 接下來進行例項化ObjectFactory, 並set進 configuration
//到此,簡單講一下configuration這個物件,其實它裡面主要儲存的都是mybatis的配置
String type = context.getStringAttribute("type");
//讀取propertie的值, 根據需要可以配置, mybatis預設實現的objectFactory沒有使用properties
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
factory.setProperties(properties);
configuration.setObjectFactory(factory);
}
}
/**
* plugins 節點解析
*/
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
//由此可見,我們在定義一個interceptor的時候,需要去實現Interceptor, 這兒先不具體講,以後會詳細講解
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
/**
* mappers 節點解析
* 這是mybatis的核心之一,這兒先簡單介紹,在接下來的文章會對它進行分析
*/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
//如果mappers節點的子節點是package, 那麼就掃描package下的檔案, 注入進configuration
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
//resource, url, class 三選一
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
//mapper對映檔案都是通過XMLMapperBuilder解析
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
本次就簡單的到此結束, 從下篇文章開始,將會開始接觸到mybatis的核心部分,不過首先還是要講mapper檔案的配置及使用, 並通過原始碼進一步深入核心。