análise de código-fonte mybaits (6) suporte básico de processamento do tipo de reflexão de módulo

    suporte básico mybaits

        Visão geral : o principal trabalho de processamento de mybaits é que os quatro módulos Executor, StatementHandler, ResultHandler e paramHandler lidam com todo o processo de execução de SQL. Nesses processos, alguns dos objetos de tipo de parâmetro de MapperStatement, SqlSource, ResultMap e ParameterMapping são processado principalmente para análise de configuração. Trabalho e, finalmente, gerar o processo de execução SQL real, e este artigo explica principalmente alguns módulos de suporte básico para facilitar a análise subsequente.

        Este artigo analisa principalmente três módulos básicos
        1, módulo de carregamento de recursos
        2, módulo de reflexão
        3, módulo de processamento de tipo

 1. Módulo de carregamento de recursos

O módulo de carregamento de recursos está no pacote io, que é composto principalmente pela classe Resources e pela classe ClassLoaderWrapper. A classe ClassLoaderWrapper fornece métodos para obter o carregador de classes, bem como métodos para carregar arquivos de recursos e classForName de acordo com o carregador de classes. Os recursos são o pacote do objeto ClassLoaderWrapper. Fornece uma série de métodos de chamada estática.


1. Parte do 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;
            }

    Em segundo lugar, o módulo de reflexão

Mybaits usa reflexão em muitos lugares, e a maioria das APIs externas chama o método de reflexão subjacente chamando o método MetaObject.Esta classe pode envolver beans ou coleções comuns e implementa identificadores de propriedade para acessar propriedades. Além disso, a classe Reflector é usada pelo módulo de reflexão para chamar o método de reflexão nativo e também é uma classe para operações funcionais subjacentes do MetaObject.

1. Caso de teste 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"));
	}

A partir do teste acima, podemos ver que MetaObject pode ser muito conveniente de usar.Ele requer operações de reflexão, como manipulação de propriedade, invocação de método, criação de instância, etc., e é compatível com o uso de coleções ou beans comuns.

    2. Módulo de aula de reflexão

    MetaObject : usado principalmente externamente, as funções foram demonstradas acima.
    Refletor : A classe de reflexão básica, que envolve todos os métodos, arquivos, Construtor, etc. métodos de reflexão de uma classe e os analisa durante a inicialização.
    MetaClass : envolve a função de reflexão e aumenta o suporte para análise de propriedade, ou seja, a forma de prop.prop.prop.
    PropertyTokenizer : um wrapper para a estrutura de propriedade na forma de prop.prop.prop.
    ObjectWrapper : interface de wrapper de objeto, que é criada por MetaObject e contém uma referência a MetaObject (usada para chamadas recursivas de classe). Existem 4 implementações, uma é BaseWrapper, uma é BeanWrapper, uma é CollectionWrapper e a outra é MapWrapper.

    3 、 Refletor

a) Primeiro, olhe para as propriedades principais e construtor

 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()]); // 可写属性名的集合
	  }

      Quando o Reflector cria o construtor, ele analisa todos os métodos, campos, construtores e outras informações da classe, que podem ser usados ​​diretamente ou para julgamento posterior. Vamos dar uma olhada no processo de análise de um método de adição.
  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 é um wrapper de Reflector e suporte de reflexão aprimorado para acessadores de propriedade prop.prop.

5 、 PropertyTokenizer

     A principal função de PropertyTokenizer é representar um formulário de símbolo de propriedade prop.prop como um objeto, por
     exemplo: list [0] .item [2] .id finalmente resolve para TempObj [name = list, IndexedName = list [0], index = 0, filhos O
     código de objeto de = item [2] .id] é implementado da seguinte forma:

 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) Primeiro, olhe para o construtor do 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 pode ser visto no construtor do MetaObject, o MetaObject criará o ObjectWrapper correspondente de acordo com o tipo de objeto a ser empacotado. MapWrapper e CollectionWrapper são a implementação de alguns métodos de contêiner e BeanWrapper é a implementação de métodos de reflexão. Cada BeanWrapper contém uma referência ao MetaObject que o criou e chama internamente o MetaClass para implementar as operações de reflexão.

     Analisamos o seguinte 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就算空值也会进行包装
		  }

A descrição acima é a maneira de definir a string de atributo de formulário de símbolo de objeto por meio da reflexão de MetaObject.A função desta classe integra as funções de todas as classes acima.
      Descrição do texto da lógica de implementação do MetaObject:
        um objeto pode ser uma coleção ou um javaBean. Se quisermos acessá-lo através do símbolo de atributo, primeiro objetivamos o símbolo de atributo e, em seguida, instanciamos diferentes ObjectWrappers de acordo com se o objeto é uma coleção ou um javabean ObjectWrapper é responsável por propriedades de reflexão ou acesso em uma coleção, propriedades de vários níveis e realizar operações pseudo-recursivas empacotando cada nível em um novo MetaObjeto. Os adereços passados ​​recursivamente estão após o segundo nível.

 

Três, módulo de processamento de tipo

 1. Introdução básica.

  A interface de nível superior para manipulação de tipo é TypeHandler, e sua forma de interface é a seguinte:

  类型处理的顶级接口是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;
	
	}

 Sua função principal é para ParameterHandler e ResultetHandler processar o parâmetro implícito da instrução preparada e o método de conversão de tipo do processamento do conjunto de resultados. E sua realização específica é a realização de diferentes processamentos para cada tipo.Vamos escolher alguns e dar uma olhada.

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 você pode ver acima, a implementação de cada tipo de processamento de tipo é relativamente simples, a chave é: por que usar esse tipo de processador, como mapeamento de parâmetro, de qual tipo de processador precisamos? Isso é para encontrar o tipo de processador de acordo com o tipo real do parâmetro. Da mesma forma, o processamento do valor de retorno pode ser baseado no tipo de valor de retorno ou na configuração de tipo do resultMap para encontrar o tipo de processador específico. O processo específico não é verificado , olhamos apenas para o tipo Como o processador está registrado e onde ele está registrado?

2. Registro de
TypeHandler TypeHandler é registrado na instância TypeHandlerRegistry no Configurn.

Propriedades 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. O uso real de processadores do tipo mybaits.

 

FIM!

 

 

 

 

 

 

 

 

 

Acho que você gosta

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