1,核心对象
Configuration: mybatis的核心配置类,里面维护了mybatis的各种属性。
Sqlsession: 一个会话,里面定义了各种操作数据库的方法,和应用层交互。
Executor: Mybatis执行器,负责生成Sql和查询缓存。
StatementHanler: 负责对JDBC Statement的操作,例如设置参数。
ParameterHandler: 负责将用户参数转换为JDBC Statement需要的参数。
ResultSetHandler: 负责数据库返回的对象转化为Java需要的。
MapperProxy: mapper接口的代理对象。
MapperStatement: 对一个(select|update|delete|insert)节点的封装,里面包含了sql语句,出参,入参等一些参数。
2,插件原理与自定义插件
如果我们想对原代码进行功能上的增强,那么我想到代理模式,mybatis中只有四个对象允许被代理拦截,Executor,StatementHanler,ParameterHandler,ResultSetHandler
2.1,以PageHelpher为例,分析开发插件的流程
2.1.1,实现Interceptor接口,在上面加上@Intercepts注解,指定拦截的类和方法(方法名称和参数类型构成了一个方法的签名),实现接口的三个方法。
intercept():覆盖被拦截对象的原有的方法
plugin():给被拦截对象生成一个代理对象。
2.1.2,在mybatis-config.xml中注册插件
2.2.3,登记插件
mybatis启动时,扫描<plugin>标签,注册到了Configuration对象中的InterceptorChain中,property里面的参数会调用setProperties方法处理。
3.1,代理和拦截的实现
3.1.1,四大对象什么时候被代理的?
Executor在openSession的时候,另外三个在SimpleExecutor调用doQuery的时候创建的。然后使用interceptorChain.pluginAll返回层层代理的对象。
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
executor = (Executor) interceptorChain.pluginAll(executor);
3.1.2,多个插件的情况下,代理能不能被代理,代理顺序和调用顺序的关系?
代理可以被代理,代理顺序是从内到外,调用顺序是从外到内。
3.1.3,谁来创建代理对象?
Plugin类,Plugin.wrap方法返回代理对象
3.1.4,被代理后,调用的是什么方法?怎么调用到原来被代理对象的方法?
举例Executor被自己写的一个拦截器(MyInterceptor)拦截
第一步:target = interceptor.plugin(target); MyInterceptor会调用Plugin.wrap返回一个代理对象。
第二步:当执行Executor的具体的方法的时候,其实执行的是Plugin中的invoke方法,里面用Invocation对被代理对象进行了封装。 return interceptor.intercept(new Invocation(target, method, args));
第三步:调用MyInterceptor中的intercept方法,接着进行我们的处理,最后我们可以调用Invocation中的process方法,执行原来对象的方法。
public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);
}
3.2,应用场景分析
水平分表:对query方法进行拦截,在接口上添加注解,获取注解上的参数进行分表,修改原Sql,例如id取模,按月分表
数据加解密:query解密,update加密。
菜单权限控制:对query方法拦截,获取方法上面的注解,根据权限配置以及用户登录信息,在Sql上加上权限过滤条件。