Take you Mybatis in getMapper () the ins and outs

getMapper usage in familiar, indicating a DAO class interface, calls his method, to return from the database, it is not feeling very magical?
Are actually implemented by the JDK dynamic proxy, getMapper return a proxy object that is usually when writing dynamic proxy, proxy object processing as well as the corresponding method is invoked after the completion of the proxy object, and like this Mybatis interface for thought , not proxy object, so, Mybatis return directly through its own after a series of operations.

Source code analysis

A load MappedStatement

First Mybatis to load all insert, select, update, delete the label under Mapper, and packaged into one MappedStatement object stored in the Map <String, MappedStatement> under Configuration, embodied in XMLStatementBuilder # parseStatementNode () and MapperBuilderAssistant # addMappedStatement () method (addMappedStatement few parameters, also 20), which this.configuration.addMappedStatement () is stored in the configuration class configuration
where the Map key for the id namespace + label, he MapperBuilderAssistant # applyCurrentNamespace () method are spliced, value i.e. a MappedStatement objects
Configuration method of addMappedStatementId splicingthere after XMLMapperBuilder # bindMapperForNamespace () the stored namespace mapper, and stored in the Configuration mapperRegistry field knownMappers. knownMapper is a map, key for the namespace, value is MapperProxyFactory object.

二、getMapper()

Start getMapper (from DefaultSqlSession under getMapper ()), the intermediate after the Configuration getMapper (), the final call getMapper (under MapperRegistry); wherein the values ​​are added in knownMappers above addMapper () in.

public class MapperRegistry {
    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
    public MapperRegistry(Configuration config) {
        this.config = config;
    }
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    	//从已知的集合中返回mapper代理工厂,
        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);
            }
        }
 ........
}

Dynamic proxy generation plant by instantiating a proxy object newInstance

public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();

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

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

    public Map<Method, MapperMethod> 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) {
	    //JDK的动态代理实现,代理对象为MapperProxy。
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

So call the methods DAO, will be transferred to the next invoke the method MapperProxy.
During execution of the determination process is not java8 default or not the method of the Object. If not, before going to the query,

public class MapperProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
        //如果是Object中的方法,则直接执行代理类的对象的对应方法
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
		//如果是默认方法,也就是java8中的default方法
            if (this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
		//从缓存中获取MapperMethod
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }
    

Get here first MapperMethod method corresponding to DAO from methodCache.

    private MapperMethod cachedMapperMethod(Method method) {
     MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
     if (mapperMethod == null) {
         mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
         this.methodCache.put(method, mapperMethod);
     }
     return mapperMethod;
 }

And generating MapperMethod.SqlCommand followed MapperMethod.MethodSignature, their two internal classes
, more MappedStatement acquired from the Configuration id in SqlCommand, in which case the first step above is added MappedStatement, the completion code and the XML layer the relational mapping, and the MappedStatement id and type extracted, if no response is received, an exception is thrown, that's why there DAO select, xml configuration, there is no reason id thrown to select.

public class MapperMethod {
   private final MapperMethod.SqlCommand command;
   private final MapperMethod.MethodSignature method;
   public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
       this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
       this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
   }
//.........
 public static class SqlCommand {
       private final String name;
       private final SqlCommandType type;

       public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
           String methodName = method.getName();
           Class<?> declaringClass = method.getDeclaringClass();
           //从Configuration中获取MappedStatement
           MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);
           if (ms == null) {
               if (method.getAnnotation(Flush.class) == null) {
                   throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName);
               }

               this.name = null;
               this.type = SqlCommandType.FLUSH;
           } else {
               this.name = ms.getId();
               this.type = ms.getSqlCommandType();
               if (this.type == SqlCommandType.UNKNOWN) {
                   throw new BindingException("Unknown execution method for: " + this.name);
               }
           }

       }

More different types of labels, perform different methods

Published 42 original articles · won praise 7 · views 7755

Guess you like

Origin blog.csdn.net/HouXinLin_CSDN/article/details/104113470