栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis源码剖析之插件interceptor执行原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis源码剖析之插件interceptor执行原理

预读

mybatis通过插件 对(Executor、StatementHandler、ParameterHandler、ResultSetHandler) 这四个 核心对象创建代理进行拦截

对mybatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的 动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象

Mybatis核心对象介绍

MyBatis的主要的核心部件有以下几个:

Configuration 初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如,插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中

SqlSessionFactory SqlSession工厂

SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能

Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护

StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。

ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,

ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;

TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换

MappedStatement MappedStatement维护了一条节点的封装,

SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql 表示动态生成的SQL语句以及相应的参数信息

准备
@Intercepts({
        // 拦截指定接口的指定方法
        @Signature(type= StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class}),
//        @Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class StatementInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("对方法进行增强....");
        // 执行原方法
        Object result = invocation.proceed();
        return result;
    }

    @Override
    public Object plugin(Object target) {
        // 调用插件,创建目标类的代理对象
        System.out.println("为 "+target+" 创建代理对象");
        return Plugin.wrap(target,this);
    }

    // 为拦截器设置参数值
    @Override
    public void setProperties(Properties properties) {
    }
}



    
    

    




    
    
        
        
        
        
    

    
        
    


    
    
        
            
            
            
            
                
                
                
                
            
        
    

    
    
        
        
    


interceptor执行原理剖析

1、mybatis在解析配置文件的时候,会创建拦截器,放入configuration中

    private void parseConfiguration(XNode root) {
        try {
            //issue #117 read properties first
            // 解析  标签
            propertiesElement(root.evalNode("properties"));
            // 解析  标签
            Properties settings = settingsAsProperties(root.evalNode("settings"));
            // 加载自定义的 VFS 实现类
            loadCustomVfs(settings);
            // 解析  标签
            typeAliasesElement(root.evalNode("typeAliases"));
            // 解析  标签
            pluginElement(root.evalNode("plugins"));
            // 解析  标签
            objectFactoryElement(root.evalNode("objectFactory"));
            // 解析  标签
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            // 解析  标签
            reflectorFactoryElement(root.evalNode("reflectorFactory"));
            // 赋值  到 Configuration 属性
            settingsElement(settings);
            // read it after objectFactory and objectWrapperFactory issue #631
            // 解析  标签
            environmentsElement(root.evalNode("environments"));
            // 解析  标签
            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            // 解析  标签
            typeHandlerElement(root.evalNode("typeHandlers"));
            // 解析  标签
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    }

Configuration中的interceptorChain

public class InterceptorChain {

    
    private final List interceptors = new ArrayList<>();

    
    public Object pluginAll(Object target) {
        for (Interceptor interceptor : interceptors) {
            target = interceptor.plugin(target);
        }
        return target;
    }

    public void addInterceptor(Interceptor interceptor) {
        interceptors.add(interceptor);
    }

    public List getInterceptors() {
        return Collections.unmodifiableList(interceptors);
    }

}

2、在创建sqlSession的时候,会创建executor,从Configuration中获取拦截器链,遍历拦截器链interceptorChain,对executor进行代理



同理 StatementHandler,paramenterHandler,ResultHandler也会通过拦截器链的方式创建代理对象,这些handler默认是需要的时候创建,而不是一开始就创建

// 创建 ParameterHandler 对象
    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        // 创建 ParameterHandler 对象
        ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
        // 应用插件
        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
        return parameterHandler;
    }

    // 创建 ResultSetHandler 对象
    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                                ResultHandler resultHandler, BoundSql boundSql) {
        // 创建 DefaultResultSetHandler 对象
        ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
        // 应用插件
        resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
        return resultSetHandler;
    }

    // 创建 StatementHandler 对象
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 创建 RoutingStatementHandler 对象
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 应用插件
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }

3、获取代理对象,代理对象调用方法,默认通过executor执行,默认先cacheExecutor,然后 baseExecutor

二级缓存所在的cacheExecutor

一级缓存所在的baseExecutor

4、通过executor执行,默认会创建statmentHandler处理sql编译,参数设置,结果处理‘

预编译sql,由于是代理对象statementHandler,那么走invoke


由于我们指定了要对StatementHandler的prepare方法进行拦截调用,所以此时invoke方法中会判断是否 对该方法进行拦截。 如果拦截的方法是目标方法,那么走拦截器

拦截器增强方法

走完增强方法,走原方法

public class Invocation {

    
    private final Object target;
    
    private final Method method;
    
    private final Object[] args;

    public Invocation(Object target, Method method, Object[] args) {
        this.target = target;
        this.method = method;
        this.args = args;
    }

    public Object getTarget() {
        return target;
    }

    public Method getMethod() {
        return method;
    }

    public Object[] getArgs() {
        return args;
    }

    
    public Object proceed() throws InvocationTargetException, IllegalAccessException {
        return method.invoke(target, args);
    }

}
总结

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/708735.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号