通过@Intercepts注解信息和@Signature注解信息可以了解到,JadeSQLInterceptor会拦截Executor.query(MappedStatement, Object, RowBounds, ResultHandler)和Executor.update(MappedStatement, Object)两个方法
@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})})
public class JadeSQLInterceptor implements Interceptor {
// ......
}
介绍完注解信息后,再来看看plugin()方法,具体实现如下:
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
其中会解析JadeSQLInterceptor中的@Intercepts和@Signature注解的信息,从而确定需要拦截的方法,然后使用JDK动态代理的方式,为JadeSQLInterceptor创建代理对象。在该代理对象中,会拦截Executor.query(MappedStatement, Object, RowBounds, ResultHandler)和Executor.update(MappedStatement, Object),拦截的具体逻辑在JadeSQLInterceptor.intercept()方法中实现的,具体
1 从调用者信息invocation中获取method信息,然后判断method是否有ShardBy注解,获取shard的param,
2 根据这个param分表策略重写sql,再将重写后的sql设置到method的arg[1]中,
3 调用target object的method方法执行后续操作
public Object intercept(Invocation invocation) throws Throwable {
//获取被拦截方法的参数列表
Object[] args = invocation.getArgs();
MappedStatement statement = (MappedStatement) args[INDEX_MAPPED_STATEMENT];
//获取dao类
Class dao = mapperClazz(statement);
//获取dao中执行的method
Method method = shardMapperMethod(statement, dao);
// 在这里判断dao的method中是否有ShardBy注解,如果有,表明需要分表操作。返回ShardBy注解的Param,后面会用到
Object shardByObject = getExecuteParamByAnnotationClass(args, method, ShardBy.class);
Modifier modifier = new Modifier(new Definition(dao), method);
BoundSql boundSql = statement.getBoundSql(args[INDEX_PARAMETER]);
// 如果需要分表则在这里进行分表分析
if (shardByObject != null) {
Configuration configuration = statement.getConfiguration();
// 获取dataSource,这个dataSource是spring的代理dataSource
DataSource dataSource = configuration.getEnvironment() != null ? configuration.getEnvironment().getDataSource() : null;
//获取method中标有Param注解的信息
Map<String, Object> params = getJadeParameters(args, method);
RouterInterpreter interpreter = BeanFactory.getBean("jade.routerInterpreter", RouterInterpreter.class);
//设置到线程变量中,后面解析sql时会用到
SQLThreadLocal.set(getSQLType(statement), boundSql.getSql(), modifier, params);
// 路由了数据源,且重写了sql语句
SQLInterpreterResult result =