SSM-Mybatis-运行原理和解析-Session运行过程

SSM-Mybatis-运行原理和解析-Session运行过程

映射器的动态代理

​ 通过代码分析:

RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);

查看Mybatis如何实现getMapper,在IDEA中通过ctrl+H查看SqlSession实现类DefaultSqlSession

//DefaultSqlSession类中的getMapper实现方法
public <T> T getMapper(Class<T> type) {
    
    
        return this.configuration.getMapper(type, this);
    }

显然使用了Configuration对象的getMapper方法,获取对应的对象。继续跟踪这个方法

//Configuration对象中的getMapper方法
   public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    
    
        return this.mapperRegistry.getMapper(type, sqlSession);
    }

可以看到使用了mapperRegistry映射器的注册器来获取对应的接口对象

//MapperRegistry中的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    
    
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
    
    
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
    
    
            try {
    
    
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
    
    
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

上面代码,首先判断是否注册一个Mapper,如果没有则会抛出异常,如果有,会启动MapperProxyFactory工厂来生成一个代理实例。继续往下看:

//MapperProxyFactory工厂类
public class MapperProxyFactory<T> {
    
    
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap();

    public MapperProxyFactory(Class<T> mapperInterface) {
    
    
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
    
    
        return this.mapperInterface;
    }

    public Map<Method, MapperMethodInvoker> getMethodCache() {
    
    
        return this.methodCache;
    }
	//看此处
    protected T newInstance(MapperProxy<T> mapperProxy) {
    
    
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{
    
    this.mapperInterface}, mapperProxy);
    }
	//看此处
    public T newInstance(SqlSession sqlSession) {
    
    
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

​ 注意注释的两个方法,Mapper映射通过动态代理实现,可以看到动态代理对接口的绑定,作用是生产动态对象(占位),代理的方法则放在MapperProxy类中。继续往下看:


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        try {
    
    
            return Object.class.equals(method.getDeclaringClass()) ? 
               	   method.invoke(this, args) : 
                   this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
        } catch (Throwable var5) {
    
    
            throw ExceptionUtil.unwrapThrowable(var5);
        }
    }

​ 使用三元运算没判断Mapper是一个动态代理,如果是,则运行invoke方法。invoke首先判断是否是一个类,Mapper是一个接口不是类,判定失败,然后生成MapperMethod对象,通过cachedMapperMethod 方法对其进行初始化,最后执行execute方法,把SqlSession和当前运行参数传递进去

​ execute源码:

public class MapperMethod {
    
    
    private final MapperMethod.SqlCommand command;
    private final MapperMethod.MethodSignature method;
    ...
    
     public Object execute(SqlSession sqlSession, Object[] args) {
    
    
        Object result;
        Object param;
        switch(this.command.getType()) {
    
    
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            break;
        case SELECT:
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
    
    
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
    
    
                //代码较长,不需全部理解,只要查看查询中常用的方法即可
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
    
    
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
    
    
                result = this.executeForCursor(sqlSession, args);
            } else {
    
    
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
                if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
    
    
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + this.command.getName());
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
    
    
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
    
    
            return result;
        }
    }
 ...   
     //注释的方法
    private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    
    
        Object param = this.method.convertArgsToSqlCommandParam(args);
        List result;
        if (this.method.hasRowBounds()) {
    
    
            RowBounds rowBounds = this.method.extractRowBounds(args);
            result = sqlSession.selectList(this.command.getName(), param, rowBounds);
        } else {
    
    
            result = sqlSession.selectList(this.command.getName(), param);
        }

        if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
    
    
            return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
        } else {
    
    
            return result;
        }
    }
}

注释代码,MapperMethod类采用命令模式运行,根据上下文跳转到许多方法,不需要全部方法看明白,讨论executeForMany,源码中,实际上最后通过SqlSession对象去运行的SQL,其他的增删改查也是类似的处理

猜你喜欢

转载自blog.csdn.net/weixin_43958223/article/details/114524932