九、Mybatis 之反射体系详解

以下完整示例请参考 mybatis 源码:https://github.com/RononoaZoro/customize-mybatis (我学习的时候抄的源码)


本文从以下几个方面介绍:

  • 1、反射简介
  • 2、Java 中反射机制 Api
  • 3、Mybatis 中对反射的应用

1、反射简介

1.1、反射机制定义

  • 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。

  • 在 Java 环境中,反射机制允许程序在执行时获取某个类自身的定义信息,如属性和方法等,也可以实现动态创建类的对象、变更属性的内容或执行特定的方法的功能。从而使 Java 具有动态语言的特性,增强了程序的灵活性和可移植性。

1.2、反射机制的作用

  • 1)、在运行时判断任意一个对象所属的类型。
  • 2)、在运行时构造任意一个类的对象。
  • 3)、在运行时判断任意一个类所具有的成员变量和方法。
  • 4)、在运行时调用任意一个对象的方法,甚至可以调用private方法。
  • 5)、注意:上述功能都是在运行时环境中,而不是在编译时环境中。

2、Java 中反射机制 Api

实现Java反射机制的 API 在 Java.lang.reflect 包下,以下是一些重要的类:

  • 1)、Class 类:描述类的信息
  • 2)、Filed 类:描述属性的信息
  • 3)、Method 类:描述方法的信息
  • 4)、Constructor 类:描述构造方法的信息
  • 5)、Array 类:提供了动态创建数组及访问数组元素的静态方法。该类中的所有方法都是静态的。

3、Mybatis 中对反射的应用

3.1、利用反射创建默认对象

3.1.1、ObjectFactory

对象工厂接口

package com.luo.ibatis.reflection.factory;

import java.util.List;
import java.util.Properties;

/**
 * @author :archer
 * @date :Created in 2021/6/15 15:38
 * @description:对象工厂接口
 * MyBatis uses an ObjectFactory to create all needed new Objects.
 * @modified By:
 */
public interface ObjectFactory {
   

  /**
   * Sets configuration properties.
   * 设置属性值
   * @param properties configuration properties
   */
  void setProperties(Properties properties);

  /**
   * Creates a new object with default constructor.
   * 使用默认构造方法创建对象
   * @param type Object type
   * @return
   */
  <T> T create(Class<T> type);

  /**
   * Creates a new object with the specified constructor and params.
   * 使用特定的构造方法创建对象
   * @param type Object type
   * @param constructorArgTypes Constructor argument types
   * @param constructorArgs Constructor argument values
   * @return
   */
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  
  /**
   * Returns true if this object can have a set of other objects.
   * It's main purpose is to support non-java.util.Collection objects like Scala collections.
   * 判断是否是集合
   * 它的主要目的是支持非 java.util.Collection 对象,如 Scala 集合。
   * @param type Object type
   * @return whether it is a collection or not
   * @since 3.1.0
   */
  <T> boolean isCollection(Class<T> type);

}

3.1.2、DefaultObjectFactory

默认工厂实现类

  • 主要提供创建一些默认的接口实现(如 List 接口是 ArrayList)
/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.luo.ibatis.reflection.factory;


import com.luo.ibatis.reflection.ReflectionException;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.*;

/**
 * @author :archer
 * @date :Created in 2021/6/15 15:38
 * @description:默认对象工厂类
 * @modified By:
 */
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) {
   
    Class<?> classToCreate = resolveInterface(type);
    // we know types are assignable(可转让的)
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }

  @Override
  public void setProperties(Properties properties) {
   
    // no props for default
  }

  /**
   * 实例化
   * @param type
   * @param constructorArgTypes
   * @param constructorArgs
   * @param <T>
   * @return
   */
  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);
    }
  }

  /**
   * 接口解析
   * @param type
   * @return
   */
  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);
  }

}

3.1.3、示例

TestClass

package com.luo.ibatis.reflection.factory;

/**
 * TestClass
 *
 * @author Ryan Lamore
 */
public class TestClass {
   
  String myString;
  Integer myInteger;

  public TestClass(String myString, Integer myInteger) {
   
    this.myString = myString;
    this.myInteger = myInteger;
  }
}

DefaultObjectFactoryTest

public class DefaultObjectFactoryTest {
   

  @Test
  public void createClass() throws Exception {
   
    DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
    TestClass testClass = defaultObjectFactory.create(TestClass.class,
        Arrays.<Class<?>>asList(String.class, Integer.class), Arrays.<Object>asList("foo", 0));

    Assert.assertEquals("myInteger didn't match expected", (Integer) 0, testClass.myInteger);
    Assert.assertEquals("myString didn't match expected", "foo", testClass.myString);
  }
    
  @Test
  public void createArrayList() throws Exception {
   
    DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
    List list = defaultObjectFactory.create(List.class);
    Assert.assertTrue(" list should be ArrayList", list instanceof ArrayList);

    Collection collection = defaultObjectFactory.create(Collection.class);
    Assert.assertTrue(" collection should be ArrayList", collection instanceof ArrayList);

    Iterable iterable = defaultObjectFactory.create(Iterable.class);
    Assert.assertTrue(" iterable should be ArrayList", iterable instanceof ArrayList);
  }
}

3.2、利用反射描述类信息

3.2.1、ReflectorFactory
  • 反射工厂接口
  • 缓存以及生成描述类信息的 Reflector 实例
package com.luo.ibatis.reflection;

/**
 * @author :archer
 * @date :Created in 2021/6/11 17:42
 * @description:反射工厂接口
 * @modified By:
 */
public interface ReflectorFactory {
   

    boolean isClassCacheEnabled();

    void setClassCacheEnabled(boolean classCacheEnabled);

    Reflector findForClass(Class<?> type);
}

3.2.2、DefaultReflectorFactory
  • ReflectorFactory 的默认实现
package com.luo.ibatis.reflection;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author :archer
 * @date :Created in 2021/6/11 17:53
 * @description:默认反射工厂类
 * @modified By:
 */
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);
        }
    }
}

3.2.3、Reflector
  • mybatis 反射体系核心类:描述类信息的类
package com.luo.ibatis.reflection;

import com.luo.ibatis.reflection.invoker.GetFieldInvoker;
import com.luo.ibatis.reflection.invoker.Invoker;
import com.luo.ibatis.reflection.invoker.MethodInvoker;
import com.luo.ibatis.reflection.invoker.SetFieldInvoker;
import com.luo.ibatis.reflection.property.PropertyNamer;

import java.lang.reflect.*;
import java.util.*;

/**
 * @author :archer
 * @date :Created in 2021/6/11 17:43
 * @description:反射执行器
 * @modified By:
 */
public class Reflector {
   

    private final Class<?> type;
    private final String[] readablePropertyNames;
    private final String[] writeablePropertyNames;
    private final Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
    private final Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
    private final Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
    private final Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
    private Constructor<?> defaultConstructor;

    private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();

    public Reflector(Class<?> clazz) {
   
        type = clazz;
        addDefaultConstructor(clazz);
        addGetMethods(clazz);
        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);
        }
    }

    private void addDefaultConstructor(Class<?> clazz) {
   
        Constructor<?>[] consts = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : consts) {
   
            if (constructor.getParameterTypes().length == 0) {
   
                if (canControlMemberAccessible()) {
   
                    try {
   
                        constructor.setAccessible(true);
                    } catch (Exception e) {
   
                        // Ignored. This is only a final precaution, nothing we can do.
                    }
                }
                if (constructor.isAccessible()) {
   
                    this.defaultConstructor = constructor;
                }
            }
        }
    }

    private void addGetMethods(Class<?> cls) {
   
        Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
        Method[] methods = getClassMethods(cls);
        for (Method method : methods) {
   
            if (method.getParameterTypes().length > 0) {
   
                continue;
            }
            String name = method.getName();
            if ((name.startsWith("get") && name.length() > 3)
                    || (name.startsWith("is") && name.length() > 2)) {
   
                name = PropertyNamer.methodToProperty(name);
                addMethodConflict(conflictingGetters, name, method);
            }
        }
        resolveGetterConflicts(conflictingGetters);
    }

    private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
   
        for 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值