análisis de código fuente mybaits (6) módulo de soporte básico-reflexión-procesamiento de tipo Io

    soporte básico mybaits

        Descripción general : el trabajo principal de procesamiento de mybaits es que los cuatro módulos de Executor, StatementHandler, ResultHandler y paramHandler manejan todo el proceso de ejecución de SQL. En estos procesos, algunos de los objetos de tipo parámetro de MapperStatement, SqlSource, ResultMap y ParameterMapping son Procesado principalmente para el análisis de la configuración Trabajar y finalmente generar el proceso de ejecución SQL real, y este artículo explica principalmente algunos módulos básicos de soporte para facilitar el análisis posterior.

        Este artículo analiza principalmente tres módulos básicos
        1, módulo de carga de recursos
        2, módulo de reflexión
        3, módulo de procesamiento de tipo

 1. Módulo de carga de recursos

El módulo de carga de recursos está bajo el paquete io, que se compone principalmente de la clase Resources y la clase ClassLoaderWrapper. La clase ClassLoaderWrapper proporciona métodos para obtener el cargador de clases, así como métodos para cargar archivos de recursos y classForName de acuerdo con el cargador de clases. Los recursos son el empaquetado del objeto ClassLoaderWrapper. Proporcionan una serie de métodos de llamada estáticos.


1. Parte del código de 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;
            }

    En segundo lugar, el módulo de reflexión

Mybaits usa la reflexión en muchos lugares, y la mayoría de las API externas llaman al método de reflexión subyacente llamando al método MetaObject. Esta clase puede envolver beans o colecciones ordinarias e implementa identificadores de propiedad para acceder a las propiedades. Además, el módulo de reflexión utiliza la clase Reflector para llamar al método de reflexión nativo, y también es una clase para operaciones funcionales subyacentes de MetaObject.

1. Caso de prueba de 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<Person> ps = new ArrayList<Person>(); // 包装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<String,Person> map = new HashMap<String,Person>(); // 包装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"));
	}

De la prueba anterior, podemos ver que MetaObject puede ser muy conveniente de usar, requiere operaciones de reflexión como manipulación de propiedades, invocación de métodos, creación de instancias, etc., y es compatible con el uso de colecciones o beans ordinarios.

    2. Clase de módulo de reflexión

    MetaObject : utilizado principalmente de forma externa, las funciones se han demostrado anteriormente.
    Reflector : la clase de reflexión básica, que envuelve todos los métodos, archivos, constructor, etc. métodos de reflexión de una clase y los analiza todos durante la inicialización.
    MetaClass : envuelve la función de reflexión y mejora el soporte para el análisis de propiedades, es decir, la forma de prop.prop.prop.
    PropertyTokenizer : un contenedor para la estructura de propiedad en forma de prop.prop.prop.
    ObjectWrapper : interfaz de contenedor de objetos, que es creada por MetaObject y contiene una referencia a MetaObject (utilizado para llamadas recursivas de clase). Hay 4 implementaciones, una es BaseWrapper, una es BeanWrapper, una es CollectionWrapper y la otra es MapWrapper.

    3 、 Reflector

a) Primero mira las propiedades principales y el constructor

 private Class<?> type;
	  private String[] readablePropertyNames = EMPTY_STRING_ARRAY; // 可读属性名数组
	  private String[] writeablePropertyNames = EMPTY_STRING_ARRAY; // 可写属性名数组
	  private Map<String, Invoker> setMethods = new HashMap<String, Invoker>(); // set方法
	  private Map<String, Invoker> getMethods = new HashMap<String, Invoker>(); // get方法
	  private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>(); // set类型
	  private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>(); // 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()]); // 可写属性名的集合
	  }

      Cuando Reflector crea el constructor, analiza todos los métodos, campos, constructores y otra información de la clase, que puede usarse directamente o para juicio posterior. Echemos un vistazo al proceso de análisis de un método de adición.
  b) método addGetMethods

 private void addGetMethods(Class<?> cls) {
	    Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>(); // 用于解决多个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<String, List<Method>> conflictingGetters) {
	    for (String propName : conflictingGetters.keySet()) {
	      List<Method> getters = conflictingGetters.get(propName);
	      Iterator<Method> 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 es una envoltura de Reflector y soporte de reflexión mejorado para los descriptores de acceso a la propiedad prop.prop.

5 、 PropertyTokenizer

     La función principal de PropertyTokenizer es representar una forma de símbolo de propiedad prop.prop como un objeto, por
     ejemplo: list [0] .item [2] .id finalmente se resuelve en TempObj [name = list, IndexedName = list [0], index = 0, niños El
     código de objeto de = item [2] .id] se implementa de la siguiente manera:

 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 、 MetaObjeto

 a) Primero mira el constructor de 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等方法。
	    }
	  }

Como se puede ver en el constructor de MetaObject, MetaObject creará el ObjectWrapper correspondiente de acuerdo con el tipo de objeto a envolver. MapWrapper y CollectionWrapper son la implementación de algunos métodos de contenedor, y BeanWrapper es la implementación de métodos de reflexión. Cada BeanWrapper tiene una referencia al MetaObject que lo creó y llama internamente a MetaClass para implementar operaciones de reflexión.

     Analizamos el siguiente método 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就算空值也会进行包装
		  }

Lo anterior es la forma de establecer la cadena de atributos de forma de símbolo de objeto a través de la reflexión de MetaObject La función de esta clase integra las funciones de todas las clases anteriores.
      Descripción del texto lógico de implementación de MetaObject:
        un objeto puede ser una colección o un javaBean. Si queremos acceder a él a través del símbolo de atributo, primero objetamos el símbolo de atributo, y luego instanciamos diferentes ObjectWrappers según si el objeto es una colección o un javabean. .ObjectWrapper es responsable de la reflexión O acceder a las propiedades en una colección, propiedades de varios niveles y realizar operaciones pseudo-recursivas empaquetando cada nivel en un nuevo MetaObject.Los accesorios pasados ​​de forma recursiva son posteriores al segundo nivel.

 

Tres, módulo de procesamiento de tipo

 1. Introducción básica.

  La interfaz de nivel superior para el manejo de tipos es TypeHandler, y su forma de interfaz es la siguiente:

  类型处理的顶级接口是TypeHandler,它的接口形式如下:
	  public interface TypeHandler<T> {
		
		/**
		 * 填充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;
	
	}

 Su función principal es que ParameterHandler y ResultetHandler procesen el parámetro implícito de la declaración preparada y el método de conversión de tipo del procesamiento del conjunto de resultados. Y su realización específica es la realización de diferentes procesamientos para cada tipo. Escojamos algunos y echemos un vistazo.

public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
	  @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);
	  }
	}

Como puede ver en lo anterior, la implementación de cada tipo de procesamiento de tipo es relativamente simple, la clave es, ¿por qué usar este tipo de procesador, como el mapeo de parámetros, qué tipo de procesador necesitamos? Esto es para encontrar el tipo de procesador de acuerdo con el tipo real del parámetro. De manera similar, el procesamiento del valor de retorno puede basarse en el tipo de valor de retorno o la configuración del tipo de resultMap para encontrar el tipo de procesador específico. El proceso específico no está verificado , solo miramos el tipo ¿Cómo está registrado el procesador y dónde está registrado?

2. El registro de
TypeHandler TypeHandler se registra en la instancia de TypeHandlerRegistry en Configurn.

Propiedades de TypeHandlerRegistry

      
        // JDBCType对应的处理器映射
        private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
        // java类型对应的处理器映射 (一个java类型可以注册多个jdbc类型,默认null的key注册的是默认的处理器)
        private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
        // 类型处理器clas和实例的映射
        private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();

Método de registro real

 private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
	    if (javaType != null) { 
	      Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
	      if (map == null) { // 创建子map
	        map = new HashMap<JdbcType, TypeHandler<?>>();
	        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. El uso real de procesadores de tipo mybaits.

 

¡FIN!

 

 

 

 

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/shuixiou1/article/details/113705958
Recomendado
Clasificación