博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybaits源码分析(六) 基础支持模块-反射-Io-类型处理
阅读量:4074 次
发布时间:2019-05-25

本文共 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");		List
ps = 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 Map
setMethods = 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/

你可能感兴趣的文章
大数据入门:Zookeeper结构体系
查看>>
大数据入门:Spark RDD基础概念
查看>>
大数据入门:SparkCore开发调优原则
查看>>
大数据入门:Java和Scala编程对比
查看>>
大数据入门:Scala函数式编程
查看>>
【数据结构周周练】002顺序表与链表
查看>>
C++报错:C4700:使用了非初始化的局部变量
查看>>
【数据结构周周练】003顺序栈与链栈
查看>>
C++类、结构体、函数、变量等命名规则详解
查看>>
C++ goto语句详解
查看>>
【数据结构周周练】008 二叉树的链式创建及测试
查看>>
《软件体系结构》 第九章 软件体系结构评估
查看>>
《软件体系结构》 第十章 软件产品线体系结构
查看>>
《软件过程管理》 第六章 软件过程的项目管理
查看>>
《软件过程管理》 第九章 软件过程的评估和改进
查看>>
分治法 动态规划法 贪心法 回溯法 小结
查看>>
《软件体系结构》 练习题
查看>>
《数据库系统概论》 第一章 绪论
查看>>
《数据库系统概论》 第二章 关系数据库
查看>>
《数据库系统概论》 第三章 关系数据库标准语言SQL
查看>>