Mybatis技术内幕(2.3.4):反射模块-ObjectFactory

基于Mybatis-3.5.0版本java

1.0 ObjectFactory对象工厂

org.apache.ibatis.reflection.factory.ObjectFactoryMybatis中不少模块都会使用到ObjectFactory接口,该接口提供了多个create()方法的重载,经过这些create()方法能够建立指定类型的对象。代码和类图以下:apache

/** * MyBatis uses an ObjectFactory to create all needed new Objects. * MyBatis使用ObjectFactory建立全部须要的新对象 * @author Clinton Begin */
public interface ObjectFactory {

	/** * Sets configuration properties. * 设置配置信息 * @param properties configuration properties */
	void setProperties(Properties properties);

	/** * Creates a new object with default constructor. * 经过无参构造器建立指定类的对象 * @param type Object type * @return */
	<T> T create(Class<T> type);

	/** * Creates a new object with the specified constructor and params. * 根据参数列表,从指定类型中选择合适的构造器建立对象 * @param type Object type * @param constructorArgTypes Constructor argument types * @param constructorArgs Constructor argument values * @return */
	<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

	/** * Returns true if this object can have a set of other objects. It's main * purpose is to support non-java.util.Collection objects like Scala * collections. * 检测指定类型是否为集合类型,主要处理java.util.Collection及其子类 * @param type Object type * @return whether it is a collection or not * @since 3.1.0 */
	<T> boolean isCollection(Class<T> type);
}
复制代码

2.0 DefaultObjectFactory

org.apache.ibatis.reflection.factory.DefaultObjectFactory是ObjectFactory的默认实现,代码比较简单看下注释就懂了,以下:数组

/** * @author Clinton Begin */
public class DefaultObjectFactory implements ObjectFactory, Serializable {

	private static final long serialVersionUID = -8855120656740914948L;

	/** * 经过无参构造器建立指定类的对象 */
	@Override
	public <T> T create(Class<T> type) {
		return create(type, null, null);
	}

	/** * 根据参数列表,从指定类型中选择合适的构造器建立对象 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
		Class<?> classToCreate = resolveInterface(type);
		// we know types are assignable
		return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
	}

	@Override
	public void setProperties(Properties properties) {
		// no props for default
	}

	/** * 根据参数列表,从指定类型中选择合适的构造器建立对象 * @param type 建立类的类型 * @param constructorArgTypes 指定构造器的参数类型列表 * @param constructorArgs 构造器参数列表 * @return */
	private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
		try {
			Constructor<T> constructor;
			// 没有constructorArgTypes和constructorArgs 则用默认无参构造器建立对象
			if (constructorArgTypes == null || constructorArgs == null) {
				constructor = type.getDeclaredConstructor();
				try {
					return constructor.newInstance();
				} catch (IllegalAccessException e) {
					if (Reflector.canControlMemberAccessible()) {
						constructor.setAccessible(true);
						return constructor.newInstance();
					} else {
						throw e;
					}
				}
			}
			// 根据指定构造器参数类型列表 找到指定构造器 建立对应对象
			constructor = type
					.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
			try {
				return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
			} catch (IllegalAccessException e) {
				if (Reflector.canControlMemberAccessible()) {
					constructor.setAccessible(true);
					return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
				} else {
					throw e;
				}
			}
		} catch (Exception e) {
			//错误日志记录
			StringBuilder argTypes = new StringBuilder();
			if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
				for (Class<?> argType : constructorArgTypes) {
					argTypes.append(argType.getSimpleName());
					argTypes.append(",");
				}
				argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
			}
			StringBuilder argValues = new StringBuilder();
			if (constructorArgs != null && !constructorArgs.isEmpty()) {
				for (Object argValue : constructorArgs) {
					argValues.append(String.valueOf(argValue));
					argValues.append(",");
				}
				argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
			}
			throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes
					+ ") or values (" + argValues + "). Cause: " + e, e);
		}
	}

	/** * 对于建立经常使用的集合接口,返回指定的默认实现 * List、Collection、Iterable 返回ArrayList * Map 返回HashMap * SortedSet 返回TreeSet * Set 返回HashSet * @param type * @return */
	protected Class<?> resolveInterface(Class<?> type) {
		Class<?> classToCreate;
		if (type == List.class || type == Collection.class || type == Iterable.class) {
			classToCreate = ArrayList.class;
		} else if (type == Map.class) {
			classToCreate = HashMap.class;
		} else if (type == SortedSet.class) { // issue #510 Collections Support
			classToCreate = TreeSet.class;
		} else if (type == Set.class) {
			classToCreate = HashSet.class;
		} else {
			classToCreate = type;
		}
		return classToCreate;
	}

	/** * 判断类是否为集合类 * isAssignableFrom Reflector类里面有介绍啦,主要针对Class为主体的判断 */
	@Override
	public <T> boolean isCollection(Class<T> type) {
		return Collection.class.isAssignableFrom(type);
	}
}
复制代码

3.0 mybatis-config 配置objectFactory

如下内容摘录自 Mybatis官网中文文档bash

MyBatis 每次建立结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂须要作的仅仅是实例化目标类,要么经过默认构造方法,要么在参数映射存在的时候经过参数构造方法来实例化。 若是想覆盖对象工厂的默认行为,则能够经过建立本身的对象工厂来实现。好比:mybatis

// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
	public Object create(Class type) {
		return super.create(type);
	}

	public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
		return super.create(type, constructorArgTypes, constructorArgs);
	}

	public void setProperties(Properties properties) {
		super.setProperties(properties);
	}

	public <T> boolean isCollection(Class<T> type) {
		return Collection.class.isAssignableFrom(type);
	}
}
复制代码
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>
复制代码

ObjectFactory 接口很简单,它包含两个建立用的方法,一个是处理默认构造方法的,另一个是处理带参数的构造方法的。 最后,setProperties方法能够被用来配置 ObjectFactory,在初始化你的ObjectFactory实例后,objectFactory元素体中定义的属性会被传递给 setProperties 方法。app

4.0 总结

本节内容比较简单主要就是利用反射去建立对象。可是有个小的知识点你们能够学习下ide

4.1 List toArray(T[] a)

在Mybatis代码中有不少List转数组转的地方,以DefaultObjectFactory代码为例:性能

type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
复制代码

像阿甘最开始的时候也没有太注意这一块,常常是直接给了一个长度为0的数组,发现也能够正常工做。如:学习

list.toArray(new String[0]);
复制代码

在实际的转换中除了指定数组类型,最好能加上数组长度。ui

为何呢? 能够先看下ArrayList的实现

// ArrayList.java
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

//Arrays.java
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
复制代码

能够看到当初始化数组指定的长度小于要转化的List的长度,则会利用反射建立一个新数组,再进行System.arraycopy操做,而指定了长度的初始化数组则会直接进行System.arraycopy操做。对性能的提高显而易见啦

失控的阿甘,乐于分享,记录点滴

相关文章
相关标签/搜索