mybatis源码-解析settings标签

解析settings标签

解析入口:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      //省略其他代码
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      settingsElement(settings);
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
public class XMLConfigBuilder extends BaseBuilder {
	private Properties settingsAsProperties(XNode context) {
		//如过出现没有settings标签就实例化默认的Properties给后面的代码提供一些初始化设置。
	    if (context == null) {
	      return new Properties();
	    }
	    //把<setting name="" value="">标签解析为Properties对象
	    Properties props = context.getChildrenAsProperties();
	    // Check that all settings are known to the configuration class
	    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
	    //如果获取的配置的<setting name="" value="">信息,name不在metaConfig中,则会抛出异常
	    //这里metaConfig中的信息是从Configuration类中解析出来的,包含set方法的属性
	    //所以在配置<setting>标签的时候,其name值可以参考configuration类中的属性,配置为小写
	    for (Object key : props.keySet()) {
	     //从metaConfig的relector中的setMethods中判断是否存在该属性,setMethods中存储的是可写的属性,
         //所以这里要到setMethods中进行判断
	      if (!metaConfig.hasSetter(String.valueOf(key))) {
	        throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
	      }
	    }
	    return props;
	  }
  }
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);

上面这行代码就解析了setting标签中的name可以配置的所有值。该方法有两个参数,一个是Configuration.class,一个是localReflectorFactory,看localReflectorFactory

private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();

DefaultReflectorFactory类:

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();

  public DefaultReflectorFactory() {
  }

  @Override
  public boolean isClassCacheEnabled() {
    return classCacheEnabled;
  }

  @Override
  public void setClassCacheEnabled(boolean classCacheEnabled) {
    this.classCacheEnabled = classCacheEnabled;
  }

  @Override
  public Reflector findForClass(Class<?> type) {
    if (classCacheEnabled) {
      // synchronized (type) removed see issue #461
      return reflectorMap.computeIfAbsent(type, Reflector::new);
    } else {
      return new Reflector(type);
    }
  }

}

然后执行MetaClass.forClass(Configuration.class, localReflectorFactory);

public class MetaClass {

  private final ReflectorFactory reflectorFactory;
  private final Reflector reflector;

  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type);
  }

  public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
    return new MetaClass(type, reflectorFactory);
  }
  //省略其他代码
}

重点看reflectorFactory.findForClass方法,这里reflectorFactory是DefaultReflectorFactory的一个实例。下面是DefaultReflectorFactory的findForClass方法,

public class DefaultReflectorFactory implements ReflectorFactory {
	  private boolean classCacheEnabled = true;
	  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
		//省略其他代码
		//type为Configuration.class
	  @Override
	  public Reflector findForClass(Class<?> type) {
	  	//初始化全局变量的时候是设置为true。
	    if (classCacheEnabled) {
	      // synchronized (type) removed see issue #461
	      return reflectorMap.computeIfAbsent(type, Reflector::new);
	    } else {
	      return new Reflector(type);
	    }
	  }

}

上面方法中,重点看Reflector::new这句方法

public class Reflector {
	public Reflector(Class<?> clazz) {
	    type = clazz;
	    //解析默认的构造方法,及无参构造方法
	    addDefaultConstructor(clazz);
	    //解析clazz中的get方法,这里的clazz指的是Configuration.class
	    addGetMethods(clazz);
	    //解析clazz中的set方法,这里的clazz指的是Configuration.class
	    addSetMethods(clazz);
	    addFields(clazz);
	    readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
	    writablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
	    for (String propName : readablePropertyNames) {
	      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
	    }
	    for (String propName : writablePropertyNames) {
	      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
	    }
  }
}

addDefaultConstructor(clazz)方法如下:

public class Reflector {
	//省略其他代码
	private void addDefaultConstructor(Class<?> clazz) {
	//获得该类的声明的构造方法
    Constructor<?>[] consts = clazz.getDeclaredConstructors();
    //对构造方法进行循环
    for (Constructor<?> constructor : consts) {
      //判断构造方法的参数是否为0,为0代表为默认的无参构造方法
      if (constructor.getParameterTypes().length == 0) {
      	//把默认的无参构造方法赋给defaultConstructor
        this.defaultConstructor = constructor;
      }
    }
  }
}

addGetMethods(clazz)方法如下:

public class Reflector {
	//省略其他代码
	private void addGetMethods(Class<?> cls) {
	//把所有的方法放入conflictingGetters中,key为属性名,value为List<Method>
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    //使用反射的放上获得cls的所有方法
    Method[] methods = getClassMethods(cls);
    //循环所有方法
    for (Method method : methods) {
      //方法的参数大于0,则结束本次循环,因为这里解析的是get方法,get方法默认不应该有参数
      if (method.getParameterTypes().length > 0) {
        continue;
      }
      String name = method.getName();
      //如果以get或is开头,且方法名称分别大于3和2,则说明是get方法
      if ((name.startsWith("get") && name.length() > 3)
          || (name.startsWith("is") && name.length() > 2)) {
        //通过方法名转化为属性名,这里用到了字符串截取,如,getUserName--userName
        name = PropertyNamer.methodToProperty(name);
        addMethodConflict(conflictingGetters, name, method);
      }
    }
    	/**处理一个属性多个get方法的情况,即conflictingGetter方法中一个key对应的value的长度大于1的情况,如下
         *key propertyName
         *value list<Method> 其长度大于1
         */ 
    resolveGetterConflicts(conflictingGetters);
  }
}
public class Reflector {
	//省略其他代码
	//如果conflictingGetters通过name得到的list是null就new ArrayList<>()一个集合添加到conflictingGetters中,结构是name->list
	private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
	    List<Method> list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList<>());
	    list.add(method);
	  }
}

这里是根据get和is开头的方法获取属性名作为键值,并且使用list作为value进行存储,为什么使用list那,我们看下面的方法

public void getUser(){}
public User getuser(){}
public List<User> getUser(){}
public void getUser(String id){}

上面三个方法都会以user为键进行存储,但是其方法名是一样的,所以这里要存储为list,即存储多个Method对象。

我们知道一个字段的属性的get或set方法,不可能出现上面的情况,所以针对上面的情况需要做处理,这里调用resolveGetterConflicts(conflicttingGetters),

public class Reflector {
	//省略其他代码
	private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
	    //循环
	    for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
	      Method winner = null;
	      String propName = entry.getKey();
	      //循环value这里value是一个List<Method>类型
	      for (Method candidate : entry.getValue()) {
	        if (winner == null) {
	          winner = candidate;
	          continue;
	        }
	        //获得get方法的返回值类型
	        Class<?> winnerType = winner.getReturnType();
	        Class<?> candidateType = candidate.getReturnType();
	        //如果winnerType和candidateType相等,
	        if (candidateType.equals(winnerType)) {
	          if (!boolean.class.equals(candidateType)) {
	            throw new ReflectionException(
	                "Illegal overloaded getter method with ambiguous type for property "
	                    + propName + " in class " + winner.getDeclaringClass()
	                    + ". This breaks the JavaBeans specification and can cause unpredictable results.");
	          } else if (candidate.getName().startsWith("is")) {
	            winner = candidate;
	          }
	        } else if (candidateType.isAssignableFrom(winnerType)) {
	          // OK getter type is descendant
	        } else if (winnerType.isAssignableFrom(candidateType)) {
	          winner = candidate;
	        } else {
	          throw new ReflectionException(
	              "Illegal overloaded getter method with ambiguous type for property "
	                  + propName + " in class " + winner.getDeclaringClass()
	                  + ". This breaks the JavaBeans specification and can cause unpredictable results.");
	        }
	      }
	      //最后调用addGetMethod方法,
	      addGetMethod(propName, winner);
	    }
  }
}

public class Reflector {
	private void addGetMethod(String name, Method method) {
		//校验字符
	    if (isValidPropertyName(name)) {
	      getMethods.put(name, new MethodInvoker(method));
	      Type returnType = TypeParameterResolver.resolveReturnType(method, type);
	      getTypes.put(name, typeToClass(returnType));
	    }
  }
}

把数据放到getMethods和getTyps中,分别存储了get方法和返回值。
addSetMethods方法和其处理过程类似,最终把set方法和返回值放到了setMethods和setTypes中。

addFileds(clazz)方法即是处理clazz中的属性,方法如下:

public class Reflector {
	private void addFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      //setMethods中是否包含了field.getName()的set方法
      if (!setMethods.containsKey(field.getName())) {
        // issue #379 - removed the check for final because JDK 1.5 allows
        // modification of final fields through reflection (JSR-133). (JGB)
        // pr #16 - final static can only be set by the classloader
        //获取字段的修饰符
        int modifiers = field.getModifiers();
        //modifiers 是否是final和是否是Static
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
          addSetField(field);
        }
      }
      //getMethods中是否包含了field.getName()的get方法
      if (!getMethods.containsKey(field.getName())) {
        addGetField(field);
      }
    }
    //判断是否有父类
    if (clazz.getSuperclass() != null) {
      //这里递归调用父类
      addFields(clazz.getSuperclass());
    }
  }
}

然后我们回到XMLConfigBuilder中,校验配置的setting标签中的name是否存在

public class XMLConfigBuilder extends BaseBuilder {
	private Properties settingsAsProperties(XNode context) {
	    if (context == null) {
	      return new Properties();
	    }
	    Properties props = context.getChildrenAsProperties();
	    // Check that all settings are known to the configuration class
	    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
	    //这里循环<settings>下的子标签<setting/>
	    for (Object key : props.keySet()) {
	    //从metaConfig的relector中的setMethods中判断是否存在该属性,setMethods中存储的是可写的属性,
        //所以这里要到setMethods中进行判断
	      if (!metaConfig.hasSetter(String.valueOf(key))) {
	        throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
	      }
	    }
	    return props;
	  }
}
public boolean hasSetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      if (reflector.hasSetter(prop.getName())) {
        MetaClass metaProp = metaClassForProperty(prop.getName());
        return metaProp.hasSetter(prop.getChildren());
      } else {
        return false;
      }
    } else {
      return reflector.hasSetter(prop.getName());
    }
  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值