介绍MyBatis工具类,包括资源文件读取,反射器功能,解析工具类,了解了这些基础工具类,对后面阅读其余源码很是有帮助。html
资源文件读取工具类 位于项目 org.apache.ibatis.io 参考MyBatis源码结构java
类经过类加载器简化对资源的访问。主要实现读取classpath包下的资源文件node
经过搜索Resources被引用的地方,有2个用途:git
如图: github
/** * Returns a resource on the classpath as a Reader object * 将classpath下的资源文件以字符流对象返回 * * @param resource The resource to find * @return The resource * @throws java.io.IOException If the resource cannot be found or read */ public static Reader getResourceAsReader(String resource) throws IOException { Reader reader; if (charset == null) { reader = new InputStreamReader(getResourceAsStream(resource)); } else { reader = new InputStreamReader(getResourceAsStream(resource), charset); } return reader; } /** * Returns a resource on the classpath as a Stream object * 资源文件以文件流返回 * * @param loader The classloader used to fetch the resource * @param resource The resource to find * @return The resource * @throws java.io.IOException If the resource cannot be found or read */ public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader); if (in == null) { throw new IOException("Could not find resource " + resource); } return in; } /** * Loads a class * 加载类 * * @param className - the class to fetch * @return The loaded class * @throws ClassNotFoundException If the class cannot be found (duh!) */ public static Class<?> classForName(String className) throws ClassNotFoundException { return classLoaderWrapper.classForName(className); }
Resources中实际读取资源文件都是经过 ClassLoaderWrapper 实现spring
/*** * A class to wrap access to multiple class loaders making them work as one * 多个ClassLoader包装在一块儿,当作一个使用 * @author Clinton Begin */ public class ClassLoaderWrapper { // 省略部分代码 URL getResourceAsURL(String resource, ClassLoader[] classLoader) { URL url; //遍历ClassLoader执行资源文件加载,找到了就直接返回 for (ClassLoader cl : classLoader) { if (null != cl) { // look for the resource as passed in... url = cl.getResource(resource); // ...but some class loaders want this leading "/", so we'll add it // and try again if we didn't find the resource if (null == url) { url = cl.getResource("/" + resource); } // "It's always in the last place I look for it!" // ... because only an idiot would keep looking for it after finding it, so stop looking already. if (null != url) { return url; } } } // didn't find it anywhere. return null; } /** * 构造一个classLoader数组 * @param classLoader * @return */ ClassLoader[] getClassLoaders(ClassLoader classLoader) { return new ClassLoader[]{ classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader(), systemClassLoader}; } }
在应用服务中提供很是简单API访问资源文件。不一样的应用服务器有不一样的文件结构,有些特殊的须要进行适配,例如:JBoss6VFS。 主要是实现package这种目录式文件加载 <package name="org.apache.ibatis.builder.mapper"/>sql
配置文件事例:数据库
<mappers> <package name="org.apache.ibatis.builder.mapper"/> </mappers>
VFS 为抽象类,定义了模板方法 List<String> list(URL url, String forPath) 由子类实现, VFS是一个静态单例模式express
public abstract class VFS { private static final Log log = LogFactory.getLog(VFS.class); /** Singleton instance holder. 单例模式 */ private static class VFSHolder { static final VFS INSTANCE = createVFS(); /** * 经过静态方法实例化 * @return */ @SuppressWarnings("unchecked") static VFS createVFS() { // Try the user implementations first, then the built-ins List<Class<? extends VFS>> impls = new ArrayList<Class<? extends VFS>>(); impls.addAll(USER_IMPLEMENTATIONS); impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS)); // Try each implementation class until a valid one is found VFS vfs = null; for (int i = 0; vfs == null || !vfs.isValid(); i++) { Class<? extends VFS> impl = impls.get(i); try { vfs = impl.newInstance(); if (vfs == null || !vfs.isValid()) { if (log.isDebugEnabled()) { log.debug("VFS implementation " + impl.getName() + " is not valid in this environment."); } } } catch (InstantiationException e) { log.error("Failed to instantiate " + impl, e); return null; } catch (IllegalAccessException e) { log.error("Failed to instantiate " + impl, e); return null; } } if (log.isDebugEnabled()) { log.debug("Using VFS adapter " + vfs.getClass().getName()); } return vfs; } } /** * 获取VFS单例实例 * Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the * current environment, then this method returns null. */ public static VFS getInstance() { return VFSHolder.INSTANCE; } /** Return true if the {@link VFS} implementation is valid for the current environment. * 模板方法由子类实现 * */ public abstract boolean isValid(); /** * Recursively list the full resource path of all the resources that are children of the * resource identified by a URL. * 模板方法由子类实现 * * @param url The URL that identifies the resource to list. * @param forPath The path to the resource that is identified by the URL. Generally, this is the * value passed to {@link #getResources(String)} to get the resource URL. * @return A list containing the names of the child resources. * @throws IOException If I/O errors occur */ protected abstract List<String> list(URL url, String forPath) throws IOException; /** * Recursively list the full resource path of all the resources that are children of all the * resources found at the specified path. * 递归获取目录下的资源文件 * * @param path The path of the resource(s) to list. * @return A list containing the names of the child resources. * @throws IOException If I/O errors occur */ public List<String> list(String path) throws IOException { List<String> names = new ArrayList<String>(); for (URL url : getResources(path)) { names.addAll(list(url, path)); } return names; } }
ResoulverUtil 主要用于解析给定package目录下知足特定条件的class,从源码中能够看到,实际是调用VFS.getInstance().list(path) 解析apache
/** * Scans for classes starting at the package provided and descending into subpackages. * Each class is offered up to the Test as it is discovered, and if the Test returns * true the class is retained. Accumulated classes can be fetched by calling * {@link #getClasses()}. * 从提供的package开始扫描classes,而且递归扫描全部子package。 * 每个class被发现时都会提供一个Test(验证器),若是验证返回true,这个class会被保存起来。经过经过{@link #getClasses()}获取累计的classes。 * * @param test an instance of {@link Test} that will be used to filter classes * @param packageName the name of the package from which to start scanning for * classes, e.g. {@code net.sourceforge.stripes} */ public ResolverUtil<T> find(Test test, String packageName) { String path = getPackagePath(packageName); try { //获取目录下的全部文件 List<String> children = VFS.getInstance().list(path); for (String child : children) { if (child.endsWith(".class")) { //验证是匹配条件的Class addIfMatching(test, child); } } } catch (IOException ioe) { log.error("Could not read package: " + packageName, ioe); } return this; }
反射器功能位于项目 org.apache.ibatis.reflection 参考MyBatis源码结构
MyBatis使用ObjectFactory建立全部须要的新对象。
JDK 反射构造器的简单封装
/** * 对象建立工厂,根据Class建立真实对象 * @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) { //解析出Type的具体类型 Class<?> classToCreate = resolveInterface(type); // we know types are assignable //实例化class return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs); } @Override public void setProperties(Properties properties) { // no props for default } private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { try { Constructor<T> constructor; //无参构造 if (constructorArgTypes == null || constructorArgs == null) { constructor = type.getDeclaredConstructor(); if (!constructor.isAccessible()) { constructor.setAccessible(true); } return constructor.newInstance(); } constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()])); if (!constructor.isAccessible()) { constructor.setAccessible(true); } //含参数构造 return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()])); } 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); } } /** * 解析对象类型,模板方法子类能够重写 */ 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; } @Override public <T> boolean isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); } }
测试用例:
//无参构造 DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory(); Set set = defaultObjectFactory.create(Set.class); Assert.assertTrue(" set should be HashSet", set instanceof HashSet); //有参构造 DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory(); TestClass testClass = defaultObjectFactory.create(TestClass.class, Arrays.<Class<?>>asList(String.class, Integer.class), Arrays.<Object>asList("foo", 0));
你也能够自定义ObjectFactory,经过如下配置使用,ExampleObjectFactory在MyBatis源码包
<configuration> <objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory"> <property name="objectFactoryProperty" value="100"/> </objectFactory> </configuration>
这个类缓存了类定义信息集合,容许在属性名和getter/setter方法之间进行简单的映射
经过调用Reflector解刨对象,将属性和方法所有分离,经过属性名能够找到对应的getter/setter方法
public class Reflector { /**对象Class类型*/ private final Class<?> type; /**可读的属性名数组*/ private final String[] readablePropertyNames; /**可写的属性名数组*/ private final String[] writeablePropertyNames; /**对象的全部set方法*/ private final Map<String, Invoker> setMethods = new HashMap<String, Invoker>(); /**对象的全部get方法*/ private final Map<String, Invoker> getMethods = new HashMap<String, Invoker>(); /**对象的全部set方法参数类型*/ private final Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>(); /**对象的全部get方法返回类型*/ private final Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>(); /**对象构造器*/ private Constructor<?> defaultConstructor; /**忽略大小写的方式存储属性名,key转大写后存储,value为真实属性名,用于快速查找*/ private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>(); /*** * #mark 反射构造对象 * @param clazz */ public Reflector(Class<?> clazz) { type = clazz; //构造方法 addDefaultConstructor(clazz); //全部get方法 addGetMethods(clazz); //全部set方法 addSetMethods(clazz); //成员变量 addFields(clazz); readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); for (String propName : readablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writeablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } } //省略其余代码 }
从类图能够看出DefaultReflectorFactory依赖Reflector,那咱们来看看DefaultReflectorFactory具体实现
/** * 反射器工厂 */ public class DefaultReflectorFactory implements ReflectorFactory { /**反射器是否须要缓存,默认须要*/ private boolean classCacheEnabled = true; /**类与反射器对象映射*/ private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>(); 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 //类反射器是否存在,不存在实例化,存在则返回 Reflector cached = reflectorMap.get(type); if (cached == null) { cached = new Reflector(type); reflectorMap.put(type, cached); } return cached; } else { return new Reflector(type); } } }
测试用例:
@Test public void testGetSetterType() throws Exception { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); //获取Section反射器对象 Reflector reflector = reflectorFactory.findForClass(Section.class); //验证属性id的set方法为Long.class类型 Assert.assertEquals(Long.class, reflector.getSetterType("id")); } @Test public void testGetGetterType() throws Exception { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); Reflector reflector = reflectorFactory.findForClass(Section.class); //验证属性id的get方法为Long.class类型 Assert.assertEquals(Long.class, reflector.getGetterType("id")); } @Test public void shouldNotGetClass() throws Exception { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); Reflector reflector = reflectorFactory.findForClass(Section.class); //验证是否存在getClass方法 Assert.assertFalse(reflector.hasGetter("class")); } static interface Entity<T> { T getId(); void setId(T id); } static abstract class AbstractEntity implements Entity<Long> { private Long id; @Override public Long getId() { return id; } @Override public void setId(Long id) { this.id = id; } } static class Section extends AbstractEntity implements Entity<Long> { }
更多的调用 查看源码 ReflectorTest
元对象,操做对象的对象
为何会叫作操做对象的对象呢?
MetaObject从字面翻译为元对象。将对象转换为MetaObject对象后,就能够经过MetaObject操做源对象的全部操做。能够理解MetaObject为操做对象的对象。有点相似元编程,关与元编程能够参考知乎回答
/** * 元对象,操做对象的对象 * @author Clinton Begin */ public class MetaObject { /**原始对象*/ private final Object originalObject; /**对象包装器*/ private final ObjectWrapper objectWrapper; /**对象工厂*/ private final ObjectFactory objectFactory; /**对象包装器工厂*/ private final ObjectWrapperFactory objectWrapperFactory; /**反射器工厂*/ private final ReflectorFactory reflectorFactory; /** * 私有的元对象构造方法 * @param object * @param objectFactory * @param objectWrapperFactory * @param reflectorFactory */ private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; this.reflectorFactory = reflectorFactory; //经过原始对象类型获取对象包装器 if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { this.objectWrapper = new BeanWrapper(this, object); } } /** * 获取对象的元对象 * @param object * @param objectFactory * @param objectWrapperFactory * @param reflectorFactory * @return */ public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); } } //省略部分代码 /** * 获取属性值 * @param name * @return */ public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } } /** * 设置属性值 * @param name * @param value */ public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null && prop.getChildren() != null) { // don't instantiate child path if value is null return; } else { metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } } /** * 获取属性的元对象,由于对象属性也是对象 * @param name * @return */ public MetaObject metaObjectForProperty(String name) { Object value = getValue(name); return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory); } }
测试用例:
/** * 测试对象 */ public class RichType { /** 嵌套属性 */ private RichType richType; private String richField; private String richProperty; private Map richMap = new HashMap(); private List richList = new ArrayList() { { add("bar"); } }; //省略getter/setter } /** * 元对象测试 */ public class MetaObjectTest { /** * 属性赋值和取值 */ @Test public void shouldGetAndSetField() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richField", "foo"); assertEquals("foo", meta.getValue("richField")); } /** * 嵌套属性赋值和取值 */ @Test public void shouldGetAndSetNestedField() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richField", "foo"); assertEquals("foo", meta.getValue("richType.richField")); } /** * 嵌套对象的Map属性赋值和取值 */ @Test public void shouldGetAndSetNestedMapPair() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richMap.key", "foo"); assertEquals("foo", meta.getValue("richType.richMap.key")); } /** * 属性集合赋值和取值 */ @Test public void shouldGetAndSetListItem() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richList[0]", "foo"); assertEquals("foo", meta.getValue("richList[0]")); } //省略不少代码 }
SystemMetaObject 是MetaObject的工具类,这里就不列出来了。具体功能请下载源码查看
DefaultParameterHandler 代码
/** * #mark 设置执行参数 * * @param ps */ @Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); //参数非输出参数 if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params //参数为外部参数 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { //参数默认处理器能够处理 value = parameterObject; } else { //获取元数据对象 MetaObject metaObject = configuration.newMetaObject(parameterObject); //经过对象获值 value = metaObject.getValue(propertyName); } //获取参数类型处理器,不一样类型参数调用不一样setXXX(i,value) TypeHandler typeHandler = parameterMapping.getTypeHandler(); JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
DefaultResultSetHandler 代码
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) { // 省略部分代码 if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) { // gcode issue #377, call setter on nulls (value is not 'found') //经过元对象为属性设置值 metaObject.setValue(property, value); } }
元类,操做类的类。
MetaClass和MetaObject相似,但侧重点是对类的操做,MetaClass封装了Reflector的功能
/** * 元类,操做类的类 * @author Clinton Begin */ 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); } //省略其余代码 }
测试用例:
/** * 元类测试 */ public class MetaClassTest { @Test public void shouldTestDataTypeOfGenericMethod() { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); //获取元类对象 MetaClass meta = MetaClass.forClass(GenericConcrete.class, reflectorFactory); //属性id的返回值为Long类型 assertEquals(Long.class, meta.getGetterType("id")); assertEquals(Long.class, meta.getSetterType("id")); } /** * 验证全部属性getter返回参数类型 */ @Test public void shouldCheckTypeForEachGetter() { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory); //验证对象成员变量 assertEquals(String.class, meta.getGetterType("richField")); //验证对象属性 assertEquals(String.class, meta.getGetterType("richProperty")); //集合属性 assertEquals(List.class, meta.getGetterType("richList")); assertEquals(Map.class, meta.getGetterType("richMap")); assertEquals(List.class, meta.getGetterType("richList[0]")); assertEquals(RichType.class, meta.getGetterType("richType")); //验证嵌套属性对象的成员变量 assertEquals(String.class, meta.getGetterType("richType.richField")); assertEquals(String.class, meta.getGetterType("richType.richProperty")); assertEquals(List.class, meta.getGetterType("richType.richList")); assertEquals(Map.class, meta.getGetterType("richType.richMap")); assertEquals(List.class, meta.getGetterType("richType.richList[0]")); } //省略其余代码 }
MapperBuilderAssistant 代码
/** * 解析结果属性对应的Java类型 * @param resultType * @param property * @param javaType * @return */ private Class<?> resolveResultJavaType(Class<?> resultType, String property, Class<?> javaType) { if (javaType == null && property != null) { try { MetaClass metaResultType = MetaClass.forClass(resultType, configuration.getReflectorFactory()); javaType = metaResultType.getSetterType(property); } catch (Exception e) { //ignore, following null check statement will deal with the situation } } if (javaType == null) { javaType = Object.class; } return javaType; } /** * 解析参数对应的Java类型 * @param resultType * @param property * @param javaType * @param jdbcType * @return */ private Class<?> resolveParameterJavaType(Class<?> resultType, String property, Class<?> javaType, JdbcType jdbcType) { if (javaType == null) { if (JdbcType.CURSOR.equals(jdbcType)) { javaType = java.sql.ResultSet.class; } else if (Map.class.isAssignableFrom(resultType)) { javaType = Object.class; } else { MetaClass metaResultType = MetaClass.forClass(resultType, configuration.getReflectorFactory()); javaType = metaResultType.getGetterType(property); } } if (javaType == null) { javaType = Object.class; } return javaType; }
DefaultResultSetHandler 代码
//#mark 建立结果对象,结果集对应Java实体对象 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException { //真实对象类型 final Class<?> resultType = resultMap.getType(); //获取反射器元数据类 final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory); final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings(); if (hasTypeHandlerForResultObject(rsw, resultType)) { //是否有类型处理器 return createPrimitiveResultObject(rsw, resultMap, columnPrefix); } else if (!constructorMappings.isEmpty()) { //使用构造方法参数,构建结果对象 return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix); } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) { //接口或有默认构造 return objectFactory.create(resultType); } else if (shouldApplyAutomaticMappings(resultMap, false)) { return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix); } throw new ExecutorException("Do not know how to create an instance of " + resultType); }
解析工具类 位于项目 org.apache.ibatis.parsing
通用的占位符解析器,基于GenericTokenParser能够实现SQL占位符#{}、${} 参数的替换
SqlSourceBuilder 代码实例
/** * #mark 解析出真实的SQL,将id=#{id} 转换成 id=? * @param originalSql * @param parameterType * @param additionalParameters * @return */ public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) { ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); String sql = parser.parse(originalSql); return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }
/** * #mark 通用的占位符解析 * @author Clinton Begin */ public class GenericTokenParser { /**占位符起始符号 如: ${ */ private final String openToken; /**占位符结束符号 如: } */ private final String closeToken; /**占位符处理器*/ private final TokenHandler handler; public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) { this.openToken = openToken; this.closeToken = closeToken; this.handler = handler; } /** * 解析 * @param text * @return */ public String parse(String text) { //省略功能实现 } }
测试用例:
/** * 通用的占位符解析测试 */ public class GenericTokenParserTest { /** * 占位符处理器,实现简单的从Map中获取值 */ public static class VariableTokenHandler implements TokenHandler { private Map<String, String> variables = new HashMap<String, String>(); /** * 处理器初始化,传入map变量 * @param variables */ public VariableTokenHandler(Map<String, String> variables) { this.variables = variables; } /** * 占位符处理 * @param content * @return */ @Override public String handleToken(String content) { //返回map值 return variables.get(content); } } @Test public void shouldDemonstrateGenericTokenReplacement() { GenericTokenParser parser = new GenericTokenParser("${", "}", new VariableTokenHandler(new HashMap<String, String>() { { //初始化占位符数据字典 put("first_name", "James"); put("initial", "T"); put("last_name", "Kirk"); put("var{with}brace", "Hiya"); put("", ""); } })); assertEquals("James T Kirk reporting.", parser.parse("${first_name} ${initial} ${last_name} reporting.")); } //省略其余代码 }
解析配置文件 ${} 变量
咱们常使用这种占位符方式配置数据库链接池
/** * 解析配置文件 ${} 变量 * * @author Clinton Begin * @author Kazuki Shimizu */ public class PropertyParser { private static final String KEY_PREFIX = "org.apache.ibatis.parsing.PropertyParser."; /** * 特别的属性key,用因而否显示默认值的占位符 * @since 3.4.2 */ public static final String KEY_ENABLE_DEFAULT_VALUE = KEY_PREFIX + "enable-default-value"; /** * #mark 特别的属性key,用于分割 key 和 默认值的占位符 * @since 3.4.2 */ public static final String KEY_DEFAULT_VALUE_SEPARATOR = KEY_PREFIX + "default-value-separator"; /** * 是否开启默认值 */ private static final String ENABLE_DEFAULT_VALUE = "false"; /** * 默认值分隔符 */ private static final String DEFAULT_VALUE_SEPARATOR = ":"; private PropertyParser() { // Prevent Instantiation } /** * 解析 * @param string 解析的字符串 * @param variables * @return */ public static String parse(String string, Properties variables) { VariableTokenHandler handler = new VariableTokenHandler(variables); GenericTokenParser parser = new GenericTokenParser("${", "}", handler); return parser.parse(string); } /** * 占位符替换处理器 */ private static class VariableTokenHandler implements TokenHandler { private final Properties variables; /**是否开启默认值*/ private final boolean enableDefaultValue; /**默认分隔符*/ private final String defaultValueSeparator; private VariableTokenHandler(Properties variables) { this.variables = variables; this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE)); this.defaultValueSeparator = getPropertyValue(KEY_DEFAULT_VALUE_SEPARATOR, DEFAULT_VALUE_SEPARATOR); } private String getPropertyValue(String key, String defaultValue) { return (variables == null) ? defaultValue : variables.getProperty(key, defaultValue); } @Override public String handleToken(String content) { if (variables != null) { String key = content; //开启默认值 if (enableDefaultValue) { final int separatorIndex = content.indexOf(defaultValueSeparator); String defaultValue = null; //分隔符存在 if (separatorIndex >= 0) { //截取分隔符前面的key key = content.substring(0, separatorIndex); //截取默认值 defaultValue = content.substring(separatorIndex + defaultValueSeparator.length()); } //存在默认值 if (defaultValue != null) { //获取properties对应的值,值不存在则返回默认值 return variables.getProperty(key, defaultValue); } } //未开启默认值 if (variables.containsKey(key)) { return variables.getProperty(key); } } //以上都未匹配返回 return "${" + content + "}"; } } }
测试用例
配置文件:
<configuration> <settings> <setting name="jdbcTypeForNull" value="${settings:jdbcTypeForNull?:NULL}"/> </settings> <objectFactory type="org.apache.ibatis.submitted.global_variables_defaults.SupportClasses$CustomObjectFactory"> <property name="name" value="${objectFactory:name?:default}"/> </objectFactory> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="UNPOOLED"> <property name="driver" value="org.hsqldb.jdbcDriver" /> <property name="url" value="jdbc:hsqldb:mem:${db:name?:global_variables_defaults}" /> <property name="username" value="sa" /> </dataSource> </environment> </environments> <databaseIdProvider type="DB_VENDOR"> <property name="${productName:hsql?:HSQL Database Engine}" value="hsql"/> </databaseIdProvider> </configuration>
代码:
public class CustomizationTest { /** * 注解式的Mapper对象 */ @CacheNamespace(implementation = SupportClasses.CustomCache.class, properties = { @Property(name = "name", value = "${cache:name?:default}") }) private interface CustomDefaultValueSeparatorMapper { @Select("SELECT '${val != null ? val : 'default'}' FROM INFORMATION_SCHEMA.SYSTEM_USERS") String selectValue(@Param("val") String val); } @Test public void applyDefaultValueWhenCustomizeDefaultValueSeparator() throws IOException { //定义properties对象值 Properties props = new Properties(); //开启默认值配置 props.setProperty(PropertyParser.KEY_ENABLE_DEFAULT_VALUE, "true"); //分隔符使用 ?: props.setProperty(PropertyParser.KEY_DEFAULT_VALUE_SEPARATOR, "?:"); Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/global_variables_defaults/mybatis-config-custom-separator.xml"); //实例化SqlSessionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props); Configuration configuration = factory.getConfiguration(); //添加Mapper对象 configuration.addMapper(CustomDefaultValueSeparatorMapper.class); //测试自定义缓存对象 SupportClasses.CustomCache cache = SupportClasses.Utils.unwrap(configuration.getCache(CustomDefaultValueSeparatorMapper.class.getName())); //验证配置解析结果 Assertions.assertThat(configuration.getJdbcTypeForNull()).isEqualTo(JdbcType.NULL); Assertions.assertThat(((UnpooledDataSource) configuration.getEnvironment().getDataSource()).getUrl()) .isEqualTo("jdbc:hsqldb:mem:global_variables_defaults"); Assertions.assertThat(configuration.getDatabaseId()).isEqualTo("hsql"); Assertions.assertThat(((SupportClasses.CustomObjectFactory) configuration.getObjectFactory()).getProperties().getProperty("name")) .isEqualTo("default"); Assertions.assertThat(cache.getName()).isEqualTo("default"); //开启SqlSession SqlSession sqlSession = factory.openSession(); try { CustomDefaultValueSeparatorMapper mapper = sqlSession.getMapper(CustomDefaultValueSeparatorMapper.class); //执行selectValue Assertions.assertThat(mapper.selectValue(null)).isEqualTo("default"); } finally { sqlSession.close(); } } }
XPath形式XML解析器 XPathParser 包揽了MyBatis全部的XML文件解析
2个重要的配置文件解析入口,代码实例:
/** * #mark 配置解析入口 #20170821 * http://www.mybatis.org/mybatis-3/zh/configuration.html * @return */ public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } /** * 解析 mapper * http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html */ public void parse() { if (!configuration.isResourceLoaded(resource)) { configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } parsePendingResultMaps(); parsePendingCacheRefs(); parsePendingStatements(); }
/** * XPath形式XML解析器 * @author Clinton Begin */ public class XPathParser { /** dom 对象 */ private final Document document; /** 是否验证配置文件 */ private boolean validation; /** 实体解析器,包含XML语法定义。具体查看 {@link org.apache.ibatis.builder.xml.XMLMapperEntityResolver} */ private EntityResolver entityResolver; /** properties 变量 */ private Properties variables; private XPath xpath; p/** * 构造器 * @param reader * @param validation * @param variables * @param entityResolver */ public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) { commonConstructor(validation, variables, entityResolver); this.document = createDocument(new InputSource(reader)); } /** * 解析XML节点集合 * @param expression * @return */ public List<XNode> evalNodes(String expression) { return evalNodes(document, expression); } public List<XNode> evalNodes(Object root, String expression) { List<XNode> xnodes = new ArrayList<XNode>(); NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++) { xnodes.add(new XNode(this, nodes.item(i), variables)); } return xnodes; } /** * 解析XML节点 * @param expression * @return */ public XNode evalNode(String expression) { return evalNode(document, expression); } /** * 建立Document * @param inputSource * @return */ private Document createDocument(InputSource inputSource) { // important: this must only be called AFTER common constructor try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validation); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(false); factory.setCoalescing(false); factory.setExpandEntityReferences(true); DocumentBuilder builder = factory.newDocumentBuilder(); //设置解析器 builder.setEntityResolver(entityResolver); //XML文件验证错误处理 builder.setErrorHandler(new ErrorHandler() { @Override public void error(SAXParseException exception) throws SAXException { throw exception; } @Override public void fatalError(SAXParseException exception) throws SAXException { throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { } }); return builder.parse(inputSource); } catch (Exception e) { //XML 配置错误 throw new BuilderException("Error creating document instance. Cause: " + e, e); } } //省略其余代码 }
测试用例
配置文件:
<employee id="${id_var}"> <blah something="that"/> <first_name>Jim</first_name> <last_name>Smith</last_name> <birth_date> <year>1970</year> <month>6</month> <day>15</day> </birth_date> <height units="ft">5.8</height> <weight units="lbs">200</weight> <active>true</active> </employee>
测试代码:
public class XPathParserTest { @Test public void shouldTestXPathParserMethods() throws Exception { String resource = "resources/nodelet_test.xml"; //读取资源文件 InputStream inputStream = Resources.getResourceAsStream(resource); //实例XPathParser对象 XPathParser parser = new XPathParser(inputStream, false, null, null); //获取 <employee><birth_date><year> 节点值 assertEquals((Long)1970l, parser.evalLong("/employee/birth_date/year")); //获取 <employee id> id属性值 assertEquals("${id_var}", parser.evalString("/employee/@id")); // 省略其余代码 inputStream.close(); } }
关于MyBatis源码解读之工具类就介绍到这里。若有疑问,欢迎留言,谢谢。