本文共 13879 字,大约阅读时间需要 46 分钟。
mybaits基础支撑
概述: mybaits的核心处理工作是由Executor、StatementHandler、ResultHandler、paramHandler四个模块处理整个sql执行过程,在这些过程中,主要对配置解析的一些MapperStatement、SqlSource、ResultMap、ParameterMapping这些参数型对象,进行处理工作,最终生成真实sql执行的过程,而本文主要讲解一些基础支撑的模块,方便后续的分析。
本文主要分析三个基础模块 1、资源加载模块 2、反射模块 3、类型处理模块
一、资源加载模块
资源加载模块在io包下,主要是由Resources类、ClassLoaderWrapper类组成,ClassLoaderWrapper类提供了获得类加载器的方法,以及根据类加载器加载资源文件和classForName等方法,Resources是对ClassLoaderWrapper对象的包装,提供静态调用的一系列方法。
1、ClassLoaderWrapper的部分代码/** * 获取类加载器列表: 指定的,当前线程的,当前类的,system类加载器 */ ClassLoader[] getClassLoaders(ClassLoader classLoader) { return new ClassLoader[] { classLoader, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader(), systemClassLoader }; } ClassLoader systemClassLoader; { systemClassLoader = ClassLoader.getSystemClassLoader(); } /** * classForName :取可用的classLoader调用Class.forName */ Class classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException { for (ClassLoader cl : classLoader) { if (null != cl) { try { Class c = Class.forName(name, true, cl); if (null != c) return c; } catch (ClassNotFoundException e) { } } } throw new ClassNotFoundException("Cannot find class: " + name); } /** * getResourceAsStream :取可用的classLoader调用getResourceAsStream。 */ InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) { for (ClassLoader cl : classLoader) { if (null != cl) { InputStream returnValue = cl.getResourceAsStream(resource); if (null == returnValue) returnValue = cl.getResourceAsStream("/" + resource); if (null != returnValue) return returnValue; } } return null; }
二、 反射模块
mybaits很多地方用了反射,外部api多数通过调用的是MetaObject方法实现调用底层反射方法,这个类可以包装普通bean,也可以包装集合,并且实现了属性标示符的方式访问属性。另外Reflector类是用于反射模块调用原生反射方法,也是MetaObject的一个底层功能操作的类。
1、MetaObject测试案例
@Test public void test1(){ Person p = new Person(); MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); meta.setValue("name", "haha"); // setValue通过反射设置对象的属性 System.out.println(p.getName()); } @Test public void test2(){ Person p = new Person(); p.setName("haha"); Listps = new ArrayList (); // 包装lists MetaObject meta = MetaObject.forObject(ps, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); meta.add(p); // MetaObject传入参数如果是集合类型,可以通过add给集合添加属性。 System.out.println(ps.get(0).getName()); } @Test public void test3(){ Person p = new Person(); p.setName("haha"); Map map = new HashMap (); // 包装map MetaObject meta = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); meta.setValue("deer", p); // 通过setValue可以给map添加属性 System.out.println(map.get("deer").getName()); } /** * 属性分割符,操作内部成员对象的属性 */ @Test public void test4(){ Person p = new Person(); MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); meta.setValue("child.name", "haha"); // 可以通过.的方式调用属性的属性 System.out.println(p.getChild().getName()); // 普通方式获取 System.out.println(meta.getValue("child.name")); // 反射方式获取值,也可以用.的方式 } /** * 属性分割符,操作内部成员集合对象的属性 */ @Test public void test5(){ Person p = new Person(); p.getChildren().add(new Person()); MetaObject meta = MetaObject.forObject(p, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); meta.setValue("children[0].name", "haha"); System.out.println(p.getChildren().get(0).getName()); System.out.println(meta.getValue("children[0].name")); }
从上面测试可以看到通过MetaObject可以非常方便的使用需要通过反射进行属性操作、方法调用、创建实例等等反射的操作,并且它兼容了集合或普通bean的使用。
2、反射模块的类
MetaObject:主要外部使用类,上面已经演示功能。
Reflector:基础反射类, 将一个class的所有methods、fileds、Constructor、等等反射的方法进行包装,并且初始化的时候全部解析了。 MetaClass:包装反射功能,并且增强了属性解析的支持,即prop.prop.prop的形式。 PropertyTokenizer:对prop.prop.prop形式属性结构的包装。 ObjectWrapper:对象包装接口,它由MetaObject创建,并且持有MetaObject的引用(用于类递归调用),有4个实现,一个是BaseWrapper,一个是BeanWrapper,一个是CollectionWrapper,一个是MapWrapper。3、Reflector
a)先看一下主要属性和构造函数
private Class type; private String[] readablePropertyNames = EMPTY_STRING_ARRAY; // 可读属性名数组 private String[] writeablePropertyNames = EMPTY_STRING_ARRAY; // 可写属性名数组 private MapsetMethods = new HashMap (); // set方法 private Map getMethods = new HashMap (); // get方法 private Map > setTypes = new HashMap >(); // set类型 private Map > getTypes = new HashMap >(); // get类型 private Constructor defaultConstructor; // 默认构造函数 private Reflector(Class clazz) { type = clazz; // 指定类型 addDefaultConstructor(clazz); //解析默认构造函数 addGetMethods(clazz); // 解析所有get方法 addSetMethods(clazz); // 解析所有set方法 addFields(clazz); // 所有字段 readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); // 可读属性名的集合 writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); // 可写属性名的集合 }
Reflector在创建构造函数的时候,就解析了class所有的方法、字段、构造函数等信息,后续可直接使用或供判断。下面看看解析一个添加方法的过程。
b) addGetMethods 方法private void addGetMethods(Class cls) { Map> conflictingGetters = new HashMap >(); // 用于解决多个method冲突用 Method[] methods = getClassMethods(cls); // 得到本类父类的所有声明方法,踢出了桥接方法 for (Method method : methods) { String name = method.getName(); if (name.startsWith("get") && name.length() > 3) { // 是get方法 if (method.getParameterTypes().length == 0) { // 并且没有参数 name = PropertyNamer.methodToProperty(name); // 方法名称变成属性名 addMethodConflict(conflictingGetters, name, method); // 添加到处理冲突的map中,因为一个属性名可能对应多个方法 } } else if (name.startsWith("is") && name.length() > 2) { // 是is方法 if (method.getParameterTypes().length == 0) { name = PropertyNamer.methodToProperty(name); addMethodConflict(conflictingGetters, name, method); } } } resolveGetterConflicts(conflictingGetters); // 处理冲突 } private void resolveGetterConflicts(Map > conflictingGetters) { for (String propName : conflictingGetters.keySet()) { List getters = conflictingGetters.get(propName); Iterator iterator = getters.iterator(); Method firstMethod = iterator.next(); if (getters.size() == 1) { // 冲突只有1个method直接添加 addGetMethod(propName, firstMethod); } else { Method getter = firstMethod; Class getterType = firstMethod.getReturnType(); // 上次遍历方法的返回类型 while (iterator.hasNext()) { Method method = iterator.next(); Class methodType = method.getReturnType(); if (methodType.equals(getterType)) { throw new ReflectionException(""); // 虽然是合法重载,但是属性类型不明确,不符合规范。 } else if (methodType.isAssignableFrom(getterType)) { // 返回类型是上次的父类型,更不明确,不使用。 // OK getter type is descendant } else if (getterType.isAssignableFrom(methodType)) { // 如果当前遍历方法返回类型比上次返回类型更具体。 getter = method; // 指定此方法为当前遍历方法 getterType = methodType; // 指定成此类型 } else { throw new ReflectionException(); } } addGetMethod(propName, getter); } } }
4、MetaClass
MetaClass是对Reflector的一个包装,并且增强了对prop.prop属性访问符的反射支持。
5、 PropertyTokenizer
PropertyTokenizer主要功能就是把一个prop.prop属性符号形式用对象表示,
比如 : list[0].item[2].id 最后解析成TempObj [name=list, IndexedName=list[0], index=0, children=item[2].id]的对象 代码实现如下:public PropertyTokenizer(String fullname) { int delim = fullname.indexOf('.'); // 对象符 if (delim > -1) { // 有 name = fullname.substring(0, delim); // name第一节点 children = fullname.substring(delim + 1); // children为剩余的 } else { name = fullname; children = null; } indexedName = name; // 属性名称有可能带[]的形式 delim = name.indexOf('['); if (delim > -1) { // 如果有[ index = name.substring(delim + 1, name.length() - 1); // index为数组属性中角标 name = name.substring(0, delim); // name要去除[] } }
6、MetaObject
a) 先看MetaObject的构造函数
private Object originalObject; // 原对象 private ObjectWrapper objectWrapper; // 对象包装 private ObjectFactory objectFactory; // 对象创建工厂 private ObjectWrapperFactory objectWrapperFactory; // 忽略 private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { // 空实现 this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { // MapWrapper的包装 this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { // Collection的包装 this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { // bean的包装 this.objectWrapper = new BeanWrapper(this, object); // 如果是javabean,就包装成这个,并且传递this,是为了伪递归调用本对象的getValue等方法。 } }
从MetaObject的构造函数可以看到,MetaObject会根据待包装对象类型的不同,创建对应的ObjectWrapper,其中MapWrapper和CollectionWrapper是一些容器方法的实现,BeanWrapper是反射方法的实现。每个BeanWrapper持有创建它的MetaObject的引用,并且内部调用MetaClass实现反射操作。
我们对下面的setValue方法进行分析。
public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); // 包装属性访问符成为对象 if (prop.hasNext()) { // 判断是否有子属性 // 这里反射获取此子属性的值,这里内部调用getValue,但是只有单个name,因此不会递归获取子属性 // 获取子属性后,会包装成新的MetaObject MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // value空值包装成的默认空的MetaObject if (value == null && prop.getChildren() != null) { return; } else { // 实例化此子属性,并且反射设置到此对象中,另外包装成MetaObject metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } // 当前name属性因为有子属性需要设置,本name的属性已经实例化,并且本name属性也已经包装成了MetaValue,就可以伪递归SetValue metaValue.setValue(prop.getChildren(), value); } else { // 只设置一级属性的值。 objectWrapper.set(prop, value); } } public MetaObject metaObjectForProperty(String name) { Object value = getValue(name); // 因为name是个单节点的属性,getValue不会递归了。 return MetaObject.forObject(value, objectFactory, objectWrapperFactory); // value就算空值也会进行包装 }
上面就是通过MetaObject反射设置对象符形式属性字符串的方式,这个类的功能整合了上面所有类的功能。
MetaObject实现逻辑的文字描述: 一个对象可能是集合也可能是javaBean,我们要通过属性符方式访问,就先对属性符对象化,然后根据对象是集合还是javabean,实例化不同的ObjectWrapper, ObjectWrapper负责反射或集合方式访问属性,多级属性,通过每级包装成新的MetaObject的方式,进行伪递归操作,递归传入的prop符是第二级后的。
三、类型处理模块
1、基本介绍。
类型处理的顶级接口是TypeHandler,它的接口形式如下:
类型处理的顶级接口是TypeHandler,它的接口形式如下: public interface TypeHandler{ /** * 填充PreparedStatement的参数 */ void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * 得到结果,根据别名 */ T getResult(ResultSet rs, String columnName) throws SQLException; /** * 得到结果,根据列角标 */ T getResult(ResultSet rs, int columnIndex) throws SQLException; /** * 从CallableStatement得到结果。 */ T getResult(CallableStatement cs, int columnIndex) throws SQLException; }
其主要作用就是供ParameterHandler和ResultetHandler在处理预处理语句的参数隐射,以及结果集处理的类型转换方法。而它的具体实现,就是每种类型对应不同处理的实现,我们挑选几个看看。
public class IntegerTypeHandler extends BaseTypeHandler{ @Override public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter); } @Override public Integer getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getInt(columnName); } @Override public Integer getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getInt(columnIndex); } @Override public Integer getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getInt(columnIndex); } }
从上面看到,每个类型的类型处理的实现都是比较简单的,关键是,为什么实用这个类型处理器,比如参数映射中,我们需要哪个 类型处理器呢?这个就是根据参数的实际类型找类型处理器,同理,返回值处理,可以是根据返回值类型或者resultMap的类型配置,找到具体的类型处理器,具体过程不去查看了,我们只看看类型处理器是怎么注册的,注册到哪里?
2、TypeHandler的注册
TypeHandler是注册到Configurn中的TypeHandlerRegistry实例中。TypeHandlerRegistry的属性
// JDBCType对应的处理器映射 private final Map> JDBC_TYPE_HANDLER_MAP = new EnumMap >(JdbcType.class); // java类型对应的处理器映射 (一个java类型可以注册多个jdbc类型,默认null的key注册的是默认的处理器) private final Map >> TYPE_HANDLER_MAP = new HashMap >>(); // 类型处理器clas和实例的映射 private final Map , TypeHandler > ALL_TYPE_HANDLERS_MAP = new HashMap , TypeHandler >();
实际注册方法
private void register(Type javaType, JdbcType jdbcType, TypeHandler handler) { if (javaType != null) { Map> map = TYPE_HANDLER_MAP.get(javaType); if (map == null) { // 创建子map map = new HashMap >(); TYPE_HANDLER_MAP.put(javaType, map); } map.put(jdbcType, handler); // put进子map if (reversePrimitiveMap.containsKey(javaType)) { // 同时注册元素类型 register(reversePrimitiveMap.get(javaType), jdbcType, handler); } } ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler); }
3、mybaits类型处理器的实际使用。
END!
转载地址:http://iruni.baihongyu.com/