借鑑了讀寫分離框架,大概瞭解了實現原理,順手寫了這篇博客
- Mybitas的Dao層實際上是一個代理對象,在執行的時候先走MapperProxy.invoke()
主要代碼
pom.xml
<dependencies>
<!-- 添加log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- 添加mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.6</version>
</dependency>
<!-- 添加mysql驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.12</version>
</dependency>
</dependencies>
mybitas.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>
<!-- 指定Mybatis使用log4j -->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--
如果上面沒有指定數據庫配置的properties文件,那麼此處可以這樣直接配置
-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test1"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件,mybatis精髓, 後面纔會細講 -->
<mappers>
<mapper resource="com/dao/userDao-mapping.xml"/>
</mappers>
</configuration>
Main
package com;
import com.dao.UserDao;
import com.entity.User;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.*;
import java.io.IOException;
import java.util.Properties;
/**
* @author :liujipeng
* @date :Created in 2019/12/27 14:58
* @description:${description}
*/
public class Application {
public static void main(String[] args) {
SqlSession sqlSession = getSessionFactory().openSession();
UserDao userMapper = sqlSession.getMapper(UserDao.class);
User user = userMapper.findUserById(1);
}
private static SqlSessionFactory getSessionFactory() {
SqlSessionFactory sessionFactory = null;
String resource = "mybitas.xml";
try {
sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
} catch (IOException e) {
e.printStackTrace();
}
MyInterceptor myInterceptor = new MyInterceptor();
sessionFactory.getConfiguration().addInterceptor(myInterceptor);
return sessionFactory;
}
//攔截器
@Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
Object.class})})
static class MyInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
}
}
}
userDao-mapping.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.dao.UserDao">
<select id="findUserById" resultType="com.entity.User" >
select * from user where id = #{id}
</select>
<update id="updateUser" >
update user set name = "sds" where id = #{id}
</update>
</mapper>
關於Mapper.xml 文件的加載和"select|insert|update|delete"
的解析此次先不進行說明,全部被解析後封存在Configuration.mappedStatements<String, MappedStatement>
key就是namespace+id
形式儲存的
Interceptor和Plugin
我的application裏面在SqlSessionFactory初始化完成的時候會將自己寫的 MyInterceptor添加到 InterceptorChain 裏面。
在什麼時候進行調用呢
在獲得SqlSessionFactory後就要獲取SqlSession,此時就會發生第一次攔截
根據openSession()方法進來,我們會看到如下得到一個執行器
在打開獲取執行器的方法裏面我們可以看到獲取了所有的攔截器
這個interceptor.plugin(target)就進入了自己設置的interceptor裏面
這個Plugin.wrap
方法繼續跟進去
signatureMap
獲取的是自己在Interceptor的註解上定義的內容,key 就是type值對象,value存的是Executor.class裏面通過nethid和args得到的方法
target是newExecutor裏面傳進去的,有此處可見是CachingExecutor
對象
因此interfaces
裏面會得到一個CachingExecutor
數組對象,如下
回頭再看這個三元運算符,則會返回Plugin針對CachingExecutor
的代理對象。
然後的方法就是一路返回,直到返回SqlSession
上面這一步返回的是 MapperProxy
的代理對象,在執行xxxMapper.find()
方法的時候會走如下
然後就會走到上面這個地方,這個 executor
就是上面Plugin產生的代理對象,當執行的時候會先走 Plugin.invoke()
method.getDeclaringClass()
得到的是進入Plugin的這個方法的方法對象,在wrap()的時候已經初始化了signatureMap數據,此次是大於0的,因此就又走了
this.interceptor.intercept(new Invocation(this.target, method, args))
這個就是自定義的intercept方法中
至此,mybitas的Interceptor就結束了,後面的就是mybitas 自己的初始化各種鏈接查詢了。