• Mybatis3源码笔记(四)Configuration(续)


    1.pluginElement(root.evalNode("plugins")) 解析plugins节点(注册interceptorChain里记录对应的拦截器)
      private void pluginElement(XNode parent) throws Exception {
        if (parent != null) {
          for (XNode child : parent.getChildren()) {
            //解析interceptor对应的class名
            String interceptor = child.getStringAttribute("interceptor");
           //解析properties 
            Properties properties = child.getChildrenAsProperties();
           //根据interceptor从resolveClass里拿出class,通过反射生成实例
            Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
           //给interceptorInstance设置properties 
            interceptorInstance.setProperties(properties);
           //注册到interceptorChain里,责任链模式
            configuration.addInterceptor(interceptorInstance);
          }
        }
      }
    
      <plugins>
        <plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
          <property name="pluginProperty" value="100"/>
        </plugin>
      </plugins>
    
    public class InterceptorChain {
    
      private final List<Interceptor> 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<Interceptor> getInterceptors() {
        return Collections.unmodifiableList(interceptors);
      }
    
    }
    
    2.objectFactoryElement,objectWrapperFactoryElement,reflectorFactoryElement 这三个节点的解析都是类似反射实例化操作,就不解释了。
      private void objectFactoryElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type");
          Properties properties = context.getChildrenAsProperties();
          ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
          factory.setProperties(properties);
          configuration.setObjectFactory(factory);
        }
      }
    
      private void objectWrapperFactoryElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type");
          ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
          configuration.setObjectWrapperFactory(factory);
        }
      }
    
      private void reflectorFactoryElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type");
          ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
          configuration.setReflectorFactory(factory);
        }
      }
    
    3.settingsElement(settings) 设置其它的setting参数。
      private void settingsElement(Properties props) {
        //指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
        configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
        //指定发现自动映射目标未知列(或者未知属性类型)的行为
        configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
        //是否启用二级缓存
        configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
        //指定具有懒加载能力的对象所用到的代理工厂
        configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
       //是否启用懒加载
        configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
        //当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载
        configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
        //是否允许单一语句返回多结果集
        configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
        //使用列标签代替列名
        configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
        //设置主键自增
        configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
        //设置默认的ExecutorType
        configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
        //设置默认的Statement执行超时时间
        configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
        //设置默认获取数量
        configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
        //设置默认的ResultSet类型
        configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
        //是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射
        configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
        //设置允许在嵌套语句中使用分页(RowBounds)
        configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
        //MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
        // 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
        configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
        //当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
        configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
        //指定对象的哪个方法触发一次延迟加载
        configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
        //设置ResultHandler的安全性检查
        configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
        //设置默认的ScriptingLanguage,用来生成boundsql
        configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
        //设置默认的defaultEnumTypeHandler
        configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
        //指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。
        configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
        // 允许使用方法签名中的名称作为语句参数名称。
        configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
        //当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。
        configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
        //设置log前缀
        configuration.setLogPrefix(props.getProperty("logPrefix"));
        //设置ConfigurationFactory
        configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
        //设置shrinkWhitespacesInSql,删除sql中多余的空白字符
        configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false));
        //设置defaultSqlProviderType,动态sql拼接
        configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
      }
    
      <settings>
        <setting name="autoMappingBehavior" value="NONE"/>
        <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
        <setting name="cacheEnabled" value="false"/>
        <setting name="proxyFactory" value="CGLIB"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>
        <setting name="multipleResultSetsEnabled" value="false"/>
        <setting name="useColumnLabel" value="false"/>
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="defaultExecutorType" value="BATCH"/>
        <setting name="defaultStatementTimeout" value="10"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="defaultResultSetType" value="SCROLL_INSENSITIVE"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="safeRowBoundsEnabled" value="true"/>
        <setting name="localCacheScope" value="STATEMENT"/>
        <setting name="jdbcTypeForNull" value="${jdbcTypeForNull}"/>
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString,xxx"/>
        <setting name="safeResultHandlerEnabled" value="false"/>
        <setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.defaults.RawLanguageDriver"/>
        <setting name="callSettersOnNulls" value="true"/>
        <setting name="logPrefix" value="mybatis_"/>
        <setting name="logImpl" value="SLF4J"/>
        <setting name="vfsImpl" value="org.apache.ibatis.io.JBoss6VFS"/>
        <setting name="configurationFactory" value="java.lang.String"/>
        <setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
        <setting name="shrinkWhitespacesInSql" value="true"/>
        <setting name="defaultSqlProviderType" value="org.apache.ibatis.builder.XmlConfigBuilderTest$MySqlProvider"/>
      </settings>
    
    4.environmentsElement(root.evalNode("environments")) 解析environments
      private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
          //environment没设置的话,默认用defalut对应的value
          if (environment == null) {
            environment = context.getStringAttribute("default");
          }
          for (XNode child : context.getChildren()) {
            String id = child.getStringAttribute("id");
            //根据environment取对应的配置
            if (isSpecifiedEnvironment(id)) {
              //实例化TransactionFactory
              TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
              //实例化DataSourceFactory
              DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
              DataSource dataSource = dsFactory.getDataSource();
              Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory).dataSource(dataSource);
              //设置environment
              configuration.setEnvironment(environmentBuilder.build());
              break;
            }
          }
        }
      }
    
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC">
            <property name="" value=""/>
          </transactionManager>
          <dataSource type="UNPOOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
    
    5.databaseIdProviderElement(root.evalNode("databaseIdProvider"))解析databaseIdProvider节点(databaseId)
      private void databaseIdProviderElement(XNode context) throws Exception {
        DatabaseIdProvider databaseIdProvider = null;
        if (context != null) {
          String type = context.getStringAttribute("type");
          // awful patch to keep backward compatibility
          if ("VENDOR".equals(type)) {
            type = "DB_VENDOR";
          }
          Properties properties = context.getChildrenAsProperties();
          //实例化databaseIdProvider
          databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
          databaseIdProvider.setProperties(properties);
        }
        Environment environment = configuration.getEnvironment();
        if (environment != null && databaseIdProvider != null) {
          //根据environment中设置的dataSource取得databaseId
          String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
          //设置databaseId
          configuration.setDatabaseId(databaseId);
        }
      }
    
      <databaseIdProvider type="DB_VENDOR">
        <property name="Apache Derby" value="derby"/>
      </databaseIdProvider>
    
    6.typeHandlerElement(root.evalNode("typeHandlers"))解析typeHandlers节点,注册类型转换器(typeHandlerRegistry)
      private void typeHandlerElement(XNode parent) {
        if (parent != null) {
          for (XNode child : parent.getChildren()) {
            //package配置,老规矩直接取该路径下的所有TypeHandler类型的class注册到typeHandlerRegistry
            if ("package".equals(child.getName())) {
              String typeHandlerPackage = child.getStringAttribute("name");
              typeHandlerRegistry.register(typeHandlerPackage);
            } else {
              String javaTypeName = child.getStringAttribute("javaType");
              String jdbcTypeName = child.getStringAttribute("jdbcType");
              String handlerTypeName = child.getStringAttribute("handler");
              Class<?> javaTypeClass = resolveClass(javaTypeName);
              JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
              Class<?> typeHandlerClass = resolveClass(handlerTypeName);
              //根据下图xml中配置的三种不同的配置方式,注册到typeHandlerRegistry
              if (javaTypeClass != null) {
                if (jdbcType == null) {
                  typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
                } else {
                  typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
                }
              } else {
                typeHandlerRegistry.register(typeHandlerClass);
              }
            }
          }
        }
      }
    
      <typeHandlers>
        <typeHandler javaType="String" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
        <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
        <typeHandler handler="org.apache.ibatis.builder.CustomLongTypeHandler"/>
        <package name="org.apache.ibatis.builder.typehandler"/>
      </typeHandlers>
    
    看下只有typeHandlerClass的注册方式,其它两种都是大同小异:
      public void register(Class<?> typeHandlerClass) {
        //flag
        boolean mappedTypeFound = false;
        //取MappedTypes注解
        MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
        if (mappedTypes != null) {
          for (Class<?> javaTypeClass : mappedTypes.value()) {
            //根据MappedTypes的value值当作javaTypeClass,走javaTypeClass+typeHandlerClass的注册
            register(javaTypeClass, typeHandlerClass);
            mappedTypeFound = true;
          }
        }
        //如果没有MappedTypes注解,走只有typeHandlerClass的注册
        if (!mappedTypeFound) {
          register(getInstance(null, typeHandlerClass));
        }
      }
    
      public <T> void register(TypeHandler<T> typeHandler) {
         ...
        // (从3.1.0开始,尝试走自动发现的注册)
        if (!mappedTypeFound && typeHandler instanceof TypeReference) {
          try {
            TypeReference<T> typeReference = (TypeReference<T>) typeHandler;
            register(typeReference.getRawType(), typeHandler);
            mappedTypeFound = true;
          } catch (Throwable t) {
            // maybe users define the TypeReference with a different type and are not assignable, so just ignore it
          }
        }
        if (!mappedTypeFound) {
          register((Class<T>) null, typeHandler);
        }
      }
    
      Type getSuperclassTypeParameter(Class<?> clazz) {
        //嵌套查询反射获得带有泛型的父类
        Type genericSuperclass = clazz.getGenericSuperclass() ;
        if (genericSuperclass instanceof Class) {
          // try to climb up the hierarchy until meet something useful
          if (TypeReference.class != genericSuperclass) {
            return getSuperclassTypeParameter(clazz.getSuperclass());
          }
          throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
            + "Remove the extension or add a type parameter to it.");
        }
        //取出TypeReference<T>中的泛型的第一个参数,例如 BaseTypeHandler<BigDecimal>中的BigDecimal
        Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
        // TODO remove this when Reflector is fixed to return Types
        if (rawType instanceof ParameterizedType) {
          rawType = ((ParameterizedType) rawType).getRawType();
        }
        return rawType;
      }
    
      private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
        if (javaType != null) {
          Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
          if (map == null || map == NULL_TYPE_HANDLER_MAP) {
            map = new HashMap<>();
          }
          map.put(jdbcType, handler);
          typeHandlerMap.put(javaType, map);
        }
        allTypeHandlersMap.put(handler.getClass(), handler);
      }
    
    另外TypeHandlerRegistry在初始化的时候已经内置了一些共通的TypeHandler:
      public TypeHandlerRegistry(Configuration configuration) {
        this.unknownTypeHandler = new UnknownTypeHandler(configuration);
    
        register(Boolean.class, new BooleanTypeHandler());
        register(boolean.class, new BooleanTypeHandler());
        register(JdbcType.BOOLEAN, new BooleanTypeHandler());
        register(JdbcType.BIT, new BooleanTypeHandler());
    
        register(Byte.class, new ByteTypeHandler());
        register(byte.class, new ByteTypeHandler());
        register(JdbcType.TINYINT, new ByteTypeHandler());
    
        register(Short.class, new ShortTypeHandler());
        register(short.class, new ShortTypeHandler());
        register(JdbcType.SMALLINT, new ShortTypeHandler());
        ...
    

  • 相关阅读:
    [转载]混合高斯模型
    威流IIS日志分析器1.2版本发布
    获取datagridview列中button点击事件
    C#引用winwebmail的dll
    威流网站监控系统新增飞信提醒
    关于Server.MapPath()
    把"\"转换成"/"
    asp.net站点常见问题绵集
    动态显示系统时间
    得到一个文件夹下的文件,并将文件删除
  • 原文地址:https://www.cnblogs.com/zhou-yuan/p/14569483.html
Copyright © 2020-2023  润新知