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;
  }
}

转载于:https://my.oschina.net/u/2246410/blog/1800737

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值