这是我参与更文挑战的第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);
}
复制代码