mybatis源碼 3.2.8

簡述要點:

  • 加載xml配置信息:
    • 解析xml:my-batis.xml-->configuration-->mappers-->mapper.resource節點,建立XMLMapperBuilder
    • XMLMapperBuilder:xml解析器。
      • 調用config.configuration(resource),將其加載到loadedResources**(加的配置文件路徑)**
      • 調用bindMapperForNamespace():獲取xml的namespace經過classLoader.forName()加載對應的接口。調用configuration.mapperRegistry.getMapper(type)建立MapperProxyFactory
  • 獲取代理對象、執行對應sql:
    • session.getMapper(Class<?>):直接調用DefaultSqlSessionz中的configuration.getMapper(type, this).
    • configuration:存放了全部的環境、mapper、接口配置。
    • MapperRegistry:存放了<K=接口、V=接口工廠>knownMappers
      • MapperProxyFactory:存放了接口(mapperInterface),接口方法及Mapper.xml文件的方法 (methodCache).
        • MapperProxyFactory:先直接經過Proxy.newProxyInstance()來實現代理類。
        • new 一個MapperProxy
      • MapperProxy存放了接口動態代理方法,等待接口方法調用。
        • 當調用方法時,直接使用methodCache,找到對應的MapperMethod,執行:MapperMethod.execute()。
    • MapperMethod:方法和sql的關聯映射類。
      • 當調用 MapperMethod.execute()時,對比方法menth來執行對應的sql。
核心配置:Configuration
protected Environment environment;    //環境:事務管理、數據源(鏈接池)

  protected boolean safeRowBoundsEnabled = false;
  protected boolean safeResultHandlerEnabled = true;
  protected boolean mapUnderscoreToCamelCase = false;
  protected boolean aggressiveLazyLoading = true;
  protected boolean multipleResultSetsEnabled = true;
  protected boolean useGeneratedKeys = false;
  protected boolean useColumnLabel = true;
  protected boolean cacheEnabled = true;
  protected boolean callSettersOnNulls = false;
  protected String logPrefix;
  protected Class <? extends Log> logImpl;
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
  protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
  protected Integer defaultStatementTimeout;
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;

  protected Properties variables = new Properties();    //
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
  protected MapperRegistry mapperRegistry = new MapperRegistry(this);   '接口動態代理實例化工廠'

  protected boolean lazyLoadingEnabled = false;
  protected ProxyFactory proxyFactory;

  protected String databaseId;
  /**
   * Configuration factory class.
   * Used to create Configuration for loading deserialized unread properties.
   *
   * @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300</a> (google code)
   */
  protected Class<?> configurationFactory;
 '類型和別名的解析工廠'
  protected final InterceptorChain interceptorChain = new InterceptorChain();
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
  protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
  protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");

  protected final Set<String> loadedResources = new HashSet<String>();
  protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");

  protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
  protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
  protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
  protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();

  /*
   * A map holds cache-ref relationship. The key is the namespace that
   * references a cache bound to another namespace and the value is the
   * namespace which the actual cache is bound to.
   */
  protected final Map<String, String> cacheRefMap = new HashMap<String, String>();

 '構造器:存放了默認的別名解析類'
 public Configuration() {
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

    languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
    languageRegistry.register(RawLanguageDriver.class);
  }
  • Environment:環境:事務管理、數據源(鏈接池)
  • Properties:屬性對象,用於解析column
  • objectFactory:一個對象屬性設置工廠,經過 method.invoke() 將查詢的值存放到實例中
  • DefaultObjectWrapperFactory:對象建立工廠,用來處理MetaObject,將column的值賦給對象示例
public class MetaObject {

  private Object originalObject;    //須要設置的對象示例
  private ObjectWrapper objectWrapper;  //mathod.invoke()調用屬性的set方法將查詢的值存放到實例中
  private ObjectFactory objectFactory;
  private ObjectWrapperFactory objectWrapperFactory;    //掛載DefaultObjectWrapperFactory
  
}
  • mapperRegistry:存放的mapper及對應的xml信息,以namespace爲key
    • 添加過程:
      • 先通mybatis的核心配置,mybatis-config.xml 裏面的<mapper/>加載實際的ORM配置
    • 在ORM配置中,經過namespace查找到對應的 interface,並將interface上的註解也解析到配置信息中
    • 當使用getMapper(Class<?> type) 的時候,會經過JDK的動態代理實現一個
    • mapperRegistry 的屬性 knownMappers
      • key: namesepece的值
      • MapperProxyFactory:以interface的類加載器加載實現的實例
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
  • typeHandlerRegistry:存放了各類類型的解析方法,用來作ORM時,處理mysql返回的二進制結果
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
  private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
  private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
  private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
  • typeAliasRegistry:存放了各類別名對應的對象
private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();
  • mappedStatements:根據每一個select|update|delete|insert 的id+namespect的名稱做爲key,存放每條sql的信息
  • caches:存放cache對象
  • resultMaps:用來存放解析後的信息resultMap信息
  • parameterMaps:存放了param的信息,用於解析傳入參數轉換成sql信息
  • keyGenerators:主鍵
MapperProxyFactory 動態代理:
  • 使用:
IcStockMapper mapper = session.getMapper(IcStockMapper.class);
int count = mapper.selectByGoodsIdsCount(null);
  • getMapper()調用:
    • 調用session中的配置configuration
    • 經過configuration中的配置mapperRegistry獲取icstockMapper的動態代理
      • mapperRegistry的核心,看下文
    • 動態代理會經過 IcStockMapper 類加載器(classloader),綁定建立成mapperProxy
      • 每次getMapper()都會建立一個新的動態代理
public class MapperProxyFactory<T> {

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

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}
  • selectByGoodsIdsCount()動態調用
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);  //真實調用的地方
  }

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

}
  • mapperMethod.execute():
public class MapperMethod {

  private final SqlCommand command;
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, method);
  }

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT / command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE / command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE / command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT / command.getType()) {
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);    //mybatis的調用方法
      }
    } else {
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result / null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}
相關文章
相關標籤/搜索