mybatis 四大对象
- 1、Executor :SIMPLE、RESUE、BATCH
- 2、StatementHandler :SIMPLE、PREPARED、CALLABLE
- 3、ParameterHandler
- 4、ResultSetHandler
mybatis运行过程中,会按照需要进行上述四大对象的创建:
其中,在创建SqlSession时会进行Executor对象的创建;在执行sql语句的时候会创建StatementHandler对象的创建;在创建StatementHandler对象的过程中,会进行ParameterHandler和ResultSetHandler这两个辅助对象的创建。
mybatis拦截器的注入
- 1、首先,我们需要编写拦截器类,实现mybatis的Interceptor接口:
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
Object[] args = invocation.getArgs();
Method method = invocation.getMethod();
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
System.out.println(properties);
}
}
- 2、其次,我们需要在myabatis的配置文件中进行plugins的注册:
<plugins>
<plugin interceptor="com.huwc.interceptor.MyInterceptor"></plugin>
</plugins>
- 3、另外,我们在编写的拦截器类上添加相应的注解,来标识这个拦截器时用来拦截mybatis的什么对象的什么方法
@Intercepts(@Signature(type = StatementHandler.class, method = "update", args = {
Statement.class
}))
public class MyInterceptor implements Interceptor {
上面的注解说明:我们的这个拦截器,可以用来拦截StatementHandler的update方法。
interceptor的执行过程:
我们看到interceptor接口中总共有3个方法,分别是:setProperties、plugin和intercept。通过分析,我们可以总结出:
- 1、setProperties方法,是在mybatis启动时进行interceptor的注册时,为拦截器类来添加属性用的;
- 2、plugin方法,是在mybatis创建四大对象时,对创建的对象进行代理包装的:
- 3、intercept方法:是真正执行拦截的方法。
我们来从代码进行分析:
我们在拦截器类的每个方法上都进行断点处理,可以看到,首先被执行的方法正是setProperties方法:
可以看到,我们在创建SqlSessionFactory的过程中,会对mybatis的配置文件进行解析和加载,最终创建Configuration对象,在创建Configuration对象的过程中,会加载配置文件中的Plugins模块,此时扫描到对应的拦截器类,执行拦截器类中的setProperties方法。
接下来的断点停留的就是拦截器类的plugin方法了:
在创建SqlSession对象的时候,会创建对应的Executor对象,对象创建好之后,如果有拦截器的话,会调用对应的拦截器类的plugin方法,进行代理对象的创建。当然,如果拦截器类的注解中并没有对应的Executor的话,也不会生成代理,直接将原始的Executor对象返回:
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
接下来,就是执行数据库操作了,在执行过程中,首先是要创建StatementHandler对象,因为最终所有的跟数据库相关的操作,都是封装在了StatementHandler对象中 ,而在创建StatementHandler对象的过程中,需要两个辅助的对象:ParameterHandler和ResultSetHandler。
所以,断点再次停留的时候,是创建ParameterHandler和ResultSet对象的时候,分别判断这两个对象是否需要被代理:
上述代码中,我们可以看到ParameterHandler和ResultSetHandler对象都是在StatementHandler对象的构造器中进行创建的,调用的都是Configuration对象中的new相应方法来处理的。
再次停留断点则是StatementHandler对象创建完成后,进行代理的过程:
最终在执行StatementHandler对象的update方法时,拦截器类的intercept方法会被触发调用:
最后:我们看下Configuration对象中创建四大对象的代码:
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
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;
}
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
上述代码中,四大对象的创建过程中,都会调用拦截器链的pluginAll方法,来实现拦截处理和代理的生成。