這是我參與更文挑戰的第21天,活動詳情查看: 更文挑戰java
[TOC]程序員
mybatis運行分爲兩部分,第一部分讀取配置文件緩存到Configuration對象中。用以建立SqlSessionFactory,第二部分是SqlSession的執行過程。spring
以前咱們知道Mapper僅僅是一個接口,而不是一個邏輯實現類。可是在Java中接口是沒法執行邏輯的。這裏Mybatis就是經過動態代理實現的。關於動態代理咱們經常使用的有Jdk動態代理和cglib動態代理。兩種卻別這裏不作贅述。關於CGLIB代理在框架中使用的比較多。sql
關於動態代理就是全部的請求有一個入口,由這個入口進行分發。在開發領域的一個用途就是【負載均衡】數據庫
關於Mybatis的動態代理是使用了兩種的結合。緩存
下面看看JDK和cglib兩種實現markdown
public interface Developer {
/** * 編碼 */
void code();
/** * 解決問題 */
void debug();
}
複製代碼
public class JavaDeveloper implements Developer {
@Override
public void code() {
System.out.println("java code");
}
@Override
public void debug() {
System.out.println("java debug");
}
}
複製代碼
咱們傳統的調用方式是經過java提供的new 機制創造一個JavaDeveloper對象出來。而經過動態代理是經過java.lang.reflect.Proxy
對象建立對象調用實際方法的。session
經過newProxyInstance
方法獲取接口對象的。而這個方法須要三個參數mybatis
ClassLoader loader : 經過實際接口實例對象獲取ClassLoader Class<?>[] interfaces : 咱們抽象的接口 InvocationHandler h : 對咱們接口對象方法的調用。在調用節點咱們能夠進行咱們的業務攔截app
JavaDeveloper jDeveloper = new JavaDeveloper();
Developer developer = (Developer) Proxy.newProxyInstance(jDeveloper.getClass().getClassLoader(), jDeveloper.getClass().getInterfaces(), (proxy, method, params) -> {
if (method.getName().equals("code")) {
System.out.println("我是一個特殊的人,code以前先分析問題");
return method.invoke(jDeveloper, params);
}
if (method.getName().equals("debug")) {
System.out.println("我沒有bug");
}
return null;
});
developer.code();
developer.debug();
複製代碼
public class HelloService {
public HelloService() {
System.out.println("HelloService構造");
}
final public String sayHello(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
複製代碼
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(o, objects);
System.out.println("======插入後者通知======");
return object;
}
}
複製代碼
public static void main(String[] args) {
//代理類class文件存入本地磁盤方便咱們反編譯查看源代碼
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/root/code");
//經過CGLIB動態代理獲取代理對象過程
Enhancer enhancer = new Enhancer();
//設置enhancer對象的父類
enhancer.setSuperclass(HelloService.class);
// 設置enhancer的回調對象
enhancer.setCallback(new MyMethodInterceptor());
//建立代理對象
HelloService helloService = (HelloService) enhancer.create();
//經過代理對象調用目標方法
helloService.sayHello();
}
複製代碼
BoundSql提供三個主要的屬性 parameterMappings 、parameterObject、sql
parameterObject參數自己。咱們能夠傳遞java基本類型、POJO、Map或者@Param標註的參數。
當咱們傳遞的是java基本類型mybatis會轉換成對應的包裝對象 int -> Integer
若是咱們傳遞POJO、Map。就是對象自己
咱們傳遞多個參數且沒有@Param指定變量名則parameterObject 相似
{"1":p1,"2":p2,"param1":p1,"param2":p2}
{"key1":p1,"key2":p2,"param1":p1,"param2":p2}
MapperProxyFactory
這個類了。該類中的newInstance
方法protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
複製代碼
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
複製代碼
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
複製代碼
Executor
、StatementHandler
、ParameterHandler
、Resulthandler
四大天王顧名思義他就是一個執行器。將java提供的sql提交到數據庫。Mybatis提供了三種執行器。
Configuration.class
中newExecutor
源碼
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 獲得configuration 中的environment
final Environment environment = configuration.getEnvironment();
// 獲得configuration 中的事務工廠
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 獲取執行器
final Executor executor = configuration.newExecutor(tx, execType);
// 返回默認的SqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
複製代碼
<settings>
<!--取值範圍 SIMPLE, REUSE, BATCH -->
<setting name="defaultExecutorType" value="SIMPLE"/>
</settings>
複製代碼
factory.openSession(ExecutorType.BATCH);
複製代碼
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
複製代碼
在查看BaseStatementHandler結構咱們會發現和Executor如出一轍。一樣的Mybatis在構造RoutingStatementHandler的時候會根據setting中配置來加載不一樣的具體子類。這些子類都是繼承了BaseStatementHandler.
前一節咱們跟蹤了Executor。 咱們知道Mybatis默認的是SimpleExecutor。 StatementHandler咱們跟蹤了Mybaits默認的是PrePareStatementHandler。在SimpleExecutor執行查詢的源碼以下
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
複製代碼