手写Mybatis:第8章-把反射用到出神入化

文章目录

  • 一、目标:元对象反射类
  • 二、设计:元对象反射类
  • 三、实现:元对象反射类
    • 3.1 工程结构
    • 3.2 元对象反射类关系图
    • 3.3 反射调用者
      • 3.3.1 统一调用者接口
      • 3.3.2 方法调用者
      • 3.3.3 getter 调用者
      • 3.3.4 setter 调用者
    • 3.4 属性命名和分解标记
      • 3.4.1 属性命名器
      • 3.4.2 属性分解标记
    • 3.5 反射器解耦对象
    • 3.6 元类包装反射器
    • 3.7 对象包装器 Wrapper
      • 3.7.1 对象包装器接口
      • 3.7.2 对象包装器抽象基类
      • 3.7.3 Bean 包装器
      • 3.7.4 Collection 包装器
      • 3.7.5 MapWrapper 包装器
    • 3.8 对象包装工厂
      • 3.8.1 对象包装工厂接口
      • 3.8.2 默认对象包装工厂实现类
    • 3.9 对象工厂
      • 3.9.1 对象工厂接口
      • 3.9.2 默认对象工厂实现类
    • 3.10 元对象封装
      • 3.10.1 元对象
      • 3.10.2 系统级别元对象
    • 3.11 数据源属性设置
      • 3.11.1 无池化数据源工厂
      • 3.11.2 有池化数据源工厂
  • 四、测试:元对象反射类
    • 4.1 单元测试
    • 4.2 反射类测试
      • 4.2.1 学生实体类
      • 4.2.2 老师实体类
      • 4.2.3 反射类测试
  • 五、总结:元对象反射类

一、目标:元对象反射类

💡 在实现数据源池化时,对于属性信息的获取,采用硬编码的方式。如何采取更好的方式呢?

在这里插入图片描述

  • 在数据源获取属性信息时,也就是通过 props.getproperty("driver") 等属性,都是通过手动编码的方式获取的。但是扩展性极差。
  • 如何增强扩张性呢。 Mybatis 的源码,在这里使用了 Mybatis 自己实现的元对象反射工具类,可以完成一个对象的属性的反射填充。
  • MetaObject 元对象反射工具类
    • 元对象、对象包装器、对象工厂、对象包装工厂、Reflector 反射器

二、设计:元对象反射类

💡 什么是元对象反射工具类?

  • 当需要对一个对象的所提供的属性进行统一的设置和获取值的操作。
  • 需要把当前这个被处理的对象解耦,提取出它所有的属性和方法,并按照不同的类型进行反射处理,从而包装成一个工具包。

在这里插入图片描述

  • 整个设计过程都围绕 如何拆解对象并提供反射操作 为主。
    • 对于一个对象来说,它所包括的有对象的构造函数、对象的属性、对象的方法。
    • 而对象的方法因为都是获取和设置值的操作,所以基本都是 get/set 处理,所以需要把这些方法在对象拆解的过程中摘取出来进行保存。
  • 当真正的开始操作时,则会依赖于已经实例化的对象,对其进行属性处理。
    • 而这些处理过程实际都是使用 JDK 所提供的 反射 进行操作的。
    • 而反射过程中的方法名称、入参类型都已经被我们拆解和处理了,最终使用的时候直接调用即可。

三、实现:元对象反射类

3.1 工程结构

mybatis-step-07
|-src
	|-main
	|	|-java
	|		|-com.lino.mybatis
    |			|-binding
    |			|	|-MapperMethod.java
	|			|	|-MapperProxy.java
	|			|	|-MapperProxyFactory.java
    |			|	|-MapperRegistry.java
    |			|-builder
    |			|	|-xml
    |			|	|	|-XMLConfigBuilder.java
    |			|	|-BaseBuilder.java
	|			|-datasource
	|			|	|-druid
	|			|	|	|-DruidDataSourceFacroty.java
	|			|	|-pooled
	|			|	|	|-PooledConnection.java
	|			|	|	|-PooledDataSource.java
	|			|	|	|-PooledDataSourceFacroty.java
	|			|	|	|-PoolState.java
	|			|	|-unpooled
	|			|	|	|-UnpooledDataSource.java
	|			|	|	|-UnpooledDataSourceFacroty.java
	|			|	|-DataSourceFactory.java
	|			|-executor
	|			|	|-resultset
	|			|	|	|-DefaultResultSetHandler.java
	|			|	|	|-ResultSetHandler.java
	|			|	|-statement
	|			|	|	|-BaseStatementHandler.java
	|			|	|	|-PreparedStatementHandler.java
	|			|	|	|-SimpleStatementHandler.java
	|			|	|	|-StatementHandler.java
	|			|	|-BaseExecutor.java
	|			|	|-Executor.java
	|			|	|-SimpleExecutor.java
    |			|-io
    |			|	|-Resources.java
    |			|-mapping
    |			|	|-BoundSql.java
    |			|	|-Environment.java
    |			|	|-MappedStatement.java
    |			|	|-ParameterMapping.java
    |			|	|-SqlCommandType.java
	|			|-reflection
	|			|	|-factory
	|			|	|	|-DefaultObjectFactory.java
	|			|	|	|-ObjectFactory.java
	|			|	|-invoker
	|			|	|	|-GetFieldInvoker.java
	|			|	|	|-Invoker.java
	|			|	|	|-MethodInvoker.java
	|			|	|	|-SetFieldInvoker.java
	|			|	|-property
	|			|	|	|-PropertyNamer.java
	|			|	|	|-PropertyTokenizer.java
	|			|	|-wrapper
	|			|	|	|-BaseWrapper.java
	|			|	|	|-BeanWrapper.java
	|			|	|	|-CollectionWrapper.java
	|			|	|	|-DefaultObjectWrapperFactory.java
	|			|	|	|-MapWrapper.java
	|			|	|	|-ObjectWrapper.java
	|			|	|	|-ObjectWrapperFactory.java
	|			|	|-MetaClass.java
	|			|	|-MetaObject.java
	|			|	|-Reflector.java
	|			|	|-SystemMetaObject.java
    |			|-session
    |			|	|-defaults
    |			|	|	|-DefaultSqlSession.java
    |			|	|	|-DefaultSqlSessionFactory.java
    |			|	|-Configuration.java
    |			|	|-ResultHandler.java
    |			|	|-SqlSession.java
    |			|	|-SqlSessionFactory.java
    |			|	|-SqlSessionFactoryBuilder.java
    |			|	|-TransactionIsolationLevel.java
    |			|-transaction
    |			|	|-jdbc
    |			|	|	|-JdbcTransaction.java
    |			|	|	|-JdbcTransactionFactory.java
    |			|	|-Transaction.java
    |			|	|-TransactionFactory.java
    |			|-type
    |			|	|-JdbcType.java
    |			|	|-TypeAliasRegistry.java
	|-test
		|-java
		|	|-com.lino.mybatis.test
		|	|-dao
		|	|	|-IUserDao.java
		|	|-po
		|	|	|-Student.java
		|	|	|-Teacher.java
		|	|	|-User.java
		|	|-ApiTest.java
		|	|-ReflectionTest.java
        |-resources
        	|-mapper
        	|	|-User_Mapper.xml
        	|-mybatis-config-datasource.xml

3.2 元对象反射类关系图

在这里插入图片描述

  • Reflector 反射器类处理对象类中的 get/set 属性,包装为可调用的 Invoker 反射类。
    • 这样在对 get/set 方法反射调用时,使用方法名称获取对应的 invoke 即可 getGetInvoker(String propertyName)
  • 有了反射器的处理,之后就是对原对象的包装,由 SystemMetaObject 提供创建 MetaObject 元对象的方法。
    • 将我们需要处理的对象进行拆解和 ObjectWrapper 对象包装处理。
    • 因为一个对象的类型还需要进行一条细节的处理,以及属性信息的拆解。
    • 例如:班级[0].学生.成绩 这样的一个类中的关联类的属性,则需要进行递归的方式拆解处理后,才能设置和获取属性值。
  • 最终在 Mybatis 其他的地方,有需要属性值设定时,就可以使用反射工具包进行处理了。

3.3 反射调用者

  • 关于对象类中的属性值获取和设置可以分为 Field 字段的 get/set 还有普通的 Method 的调用。
  • 为了减少使用方的过多处理,这里可以把集中调用者的实现包装成调用策略,统一接口,不同策略,不同的实现类。

3.3.1 统一调用者接口

Invoker.java

package com.lino.mybatis.reflection.invoker;

/**
 * @description: 调用者
 */
public interface Invoker {
    /**
     * 调用
     *
     * @param target 目标对象
     * @param args   对象数组
     * @return Object
     * @throws Exception 异常
     */
    Object invoke(Object target, Object[] args) throws Exception;
    /**
     * 获取类的类型
     *
     * @return Class<?>
     */
    Class<?> getType();
}
  • 无论任何类型的反射调用,都离不开对象和入参,只要我们把这两个字段和返回结果定义的通用,就可以包住不同策略的实现类。

3.3.2 方法调用者

MethodInvoker.java

package com.lino.mybatis.reflection.invoker;

import java.lang.reflect.Method;

/**
 * @description: 方法调用者
 */
public class MethodInvoker implements Invoker {

    private Class<?> type;
    private Method method;

    public MethodInvoker(Method method) {
        this.method = method;

        // 如果只有一个参数,返回参数类型,否则返回 return 类型
        if (method.getParameterTypes().length == 1) {
            type = method.getParameterTypes()[0];
        } else {
            type = method.getReturnType();
        }
    }

    @Override
    public Object invoke(Object target, Object[] args) throws Exception {
        return method.invoke(target, args);
    }

    @Override
    public Class<?> getType() {
        return type;
    }
}
  • 提供方法反射调用处理,构造函数会传入对应的方法类型。

3.3.3 getter 调用者

GetFieldInvoker.java

package com.lino.mybatis.reflection.invoker;

import java.lang.reflect.Field;

/**
 * @description: getter 调用者
 */
public class GetFieldInvoker implements Invoker {

    private Field field;

    public GetFieldInvoker(Field field) {
        this.field = field;
    }

    @Override
    public Object invoke(Object target, Object[] args) throws Exception {
        return field.get(target);
    }

    @Override
    public Class<?> getType() {
        return field.getType();
    }
}
  • getter 方法的调用者处理,因为 get 是有返回值的,所以直接对 Field 字段操作完后直接返回结果。

3.3.4 setter 调用者

SetFieldInvoker.java

package com.lino.mybatis.reflection.invoker;

import java.lang.reflect.Field;

/**
 * @description: setter 调用者
 */
public class SetFieldInvoker implements Invoker {

    private Field field;

    public SetFieldInvoker(Field field) {
        this.field = field;
    }

    @Override
    public Object invoke(Object target, Object[] args) throws Exception {
        field.set(target, args);
        return null;
    }

    @Override
    public Class<?> getType() {
        return field.getType();
    }
}
  • setter 方法的调用者处理,因为 set 只是设置值,所以这里就是返回一个 null 就可以。

3.4 属性命名和分解标记

3.4.1 属性命名器

PropertyNamer.java

package com.lino.mybatis.reflection.property;

import java.util.Locale;

/**
 * @description: 属性命名器
 */
public class PropertyNamer {

    private PropertyNamer() {
    }

    /**
     * 方法转换为属性
     *
     * @param name 方法名称
     * @return String
     */
    public static String methodToProperty(String name) {
        if (name.startsWith("is")) {
            name = name.substring(2);
        } else if (name.startsWith("get") || name.startsWith("set")) {
            name = name.substring(3);
        } else {
            throw new RuntimeException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get', 'set'.");
        }

        /*
            如果只有1个字母,转换为小写
            如果大于1个字母,第二个字母非大写,转换为小写
         */
        if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
            name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
        }

        return name;
    }

    /**
     * 开头判断get/set/is
     *
     * @param name 名称
     * @return boolean
     */
    public static boolean isProperty(String name) {
        return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");
    }

    /**
     * 是否为getter
     *
     * @param name 名称
     * @return boolean
     */
    public static boolean isGetter(String name) {
        return name.startsWith("get") || name.startsWith("is");
    }

    /**
     * 是否为setter
     *
     * @param name 名称
     * @return boolean
     */
    public static boolean isSetter(String name) {
        return name.startsWith("set");
    }
}

3.4.2 属性分解标记

PropertyTokenizer.java

package com.lino.mybatis.reflection.property;

import java.util.Iterator;

/**
 * @description: 属性分解标记
 */
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {

    // 例子:班级[0].学生.成绩
    /**
     * 属性名称:班级
     */
    private String name;
    /**
     * 属性对象名称:班级[0]
     */
    private String indexedName;

    /**
     * 属性索引:0
     */
    private String index;

    /**
     * 子属性:学生
     */
    private String children;

    public PropertyTokenizer(String fullName) {
        // 班级[0].学生.成绩:找.
        int delim = fullName.indexOf(".");
        if (delim > -1) {
            name = fullName.substring(0, delim);
            children = fullName.substring(delim + 1);
        } else {
            // 找不到.的话,取全部部分
            name = fullName;
            children = null;
        }
        indexedName = name;
        // 把中括号里的数字解析出来
        delim = name.indexOf("[");
        if (delim > -1) {
            index = name.substring(delim + 1, name.length() - 1);
            name = name.substring(0, delim);
        }
    }

    @Override
    public Iterator<PropertyTokenizer> iterator() {
        return this;
    }

    @Override
    public boolean hasNext() {
        return children != null;
    }

    @Override
    public PropertyTokenizer next() {
        return new PropertyTokenizer(children);
    }

    public String getName() {
        return name;
    }

    public String getIndexedName() {
        return indexedName;
    }

    public String getIndex() {
        return index;
    }

    public String getChildren() {
        return children;
    }
}

3.5 反射器解耦对象

  • Reflector 反射器专门用于解耦对象信息,只有把一个对象信息所包含的属性、方法以及关联的类都以此解析出来,才能满足后续对属性值的设置和获取。

Reflector.java

package com.lino.mybatis.reflection;

import com.lino.mybatis.reflection.invoker.GetFieldInvoker;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.invoker.MethodInvoker;
import com.lino.mybatis.reflection.invoker.SetFieldInvoker;
import com.lino.mybatis.reflection.property.PropertyNamer;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: 反射器,属性 get/set 的映射器
 */
public class Reflector {

    private static boolean classCacheEnabled = true;

    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    /**
     * 线程安全的缓存
     */
    private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<>();

    private Class<?> type;
    /**
     * get 属性列表
     */
    private String[] readablePropertyNames = EMPTY_STRING_ARRAY;
    /**
     * set 属性列表
     */
    private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;
    /**
     * set 方法列表
     */
    private Map<String, Invoker> setMethods = new HashMap<>(16);
    /**
     * get 方法列表
     */
    private Map<String, Invoker> getMethods = new HashMap<>(16);
    /**
     * set 类型列表
     */
    private Map<String, Class<?>> setTypes = new HashMap<>(16);
    /**
     * get 类型列表
     */
    private Map<String, Class<?>> getTypes = new HashMap<>(16);

    /**
     * 构造函数
     */
    private Constructor<?> defaultConstructor;

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

    public Reflector(Class<?> clazz) {
        this.type = clazz;
        // 加入构造函数
        addDefaultConstructor(clazz);
        // 加入getter
        addGetMethods(clazz);
        // 加入setter
        addSetMethods(clazz);
        // 加入字段
        addFields(clazz);
        readablePropertyNames = getMethods.keySet().toArray(new String[0]);
        writeablePropertyNames = setMethods.keySet().toArray(new String[0]);
        for (String propertyName : readablePropertyNames) {
            caseInsensitivePropertyMap.put(propertyName.toUpperCase(Locale.ENGLISH), propertyName);
        }

        for (String propertyName : writeablePropertyNames) {
            caseInsensitivePropertyMap.put(propertyName.toUpperCase(Locale.ENGLISH), propertyName);
        }
    }

    /**
     * 加入构造函数
     *
     * @param clazz 对象类型
     */
    private void addDefaultConstructor(Class<?> clazz) {
        Constructor<?>[] constes = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constes) {
            if (constructor.getParameterTypes().length == 0) {
                if (canAccessPrivateMethods()) {
                    try {
                        constructor.setAccessible(true);
                    } catch (Exception ignore) {

                    }
                }
                if (constructor.isAccessible()) {
                    this.defaultConstructor = constructor;
                }
            }
        }
    }

    /**
     * 加入getter方法
     *
     * @param clazz 对象类型
     */
    private void addGetMethods(Class<?> clazz) {
        Map<String, List<Method>> conflictingGetters = new HashMap<>(16);
        Method[] methods = getClassMethods(clazz);
        for (Method method : methods) {
            String name = method.getName();
            if (name.startsWith("get") && name.length() > 3) {
                if (method.getParameterTypes().length == 0) {
                    name = PropertyNamer.methodToProperty(name);
                    addMethodConflict(conflictingGetters, name, method);
                }
            } else if (name.startsWith("is") && name.length() > 2) {
                if (method.getParameterTypes().length == 0) {
                    name = PropertyNamer.methodToProperty(name);
                    addMethodConflict(conflictingGetters, name, method);
                }
            }
        }
        resolveGetterConflicts(conflictingGetters);
    }

    /**
     * 加入setter方法
     *
     * @param clazz 对象类型
     */
    private void addSetMethods(Class<?> clazz) {
        Map<String, List<Method>> conflictingSetters = new HashMap<>(16);
        Method[] methods = getClassMethods(clazz);
        for (Method method : methods) {
            String name = method.getName();
            if (name.startsWith("set") && name.length() > 3) {
                if (method.getParameterTypes().length == 1) {
                    name = PropertyNamer.methodToProperty(name);
                    addMethodConflict(conflictingSetters, name, method);
                }
            }
        }
        resolveSetterConflicts(conflictingSetters);
    }

    /**
     * 加入字段
     *
     * @param clazz 对象类型
     */
    private void addFields(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (canAccessPrivateMethods()) {
                try {
                    field.setAccessible(true);
                } catch (Exception e) {

                }
            }
            if (field.isAccessible()) {
                if (!setMethods.containsKey(field.getName())) {
                    int modifiers = field.getModifiers();
                    if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
                        addSetField(field);
                    }
                }
                if (!getMethods.containsKey(field.getName())) {
                    addGetField(field);
                }
            }
        }
        if (clazz.getSuperclass() != null) {
            addFields(clazz.getSuperclass());
        }
    }

    private boolean canAccessPrivateMethods() {
        try {
            SecurityManager securityManager = System.getSecurityManager();
            if (null != securityManager) {
                securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
            }
        } catch (SecurityException e) {
            return false;
        }
        return true;
    }

    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) {
                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 RuntimeException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
                    } else if (methodType.isAssignableFrom(getterType)) {
                        // OK getter type is descendant
                    } else if (getterType.isAssignableFrom(methodType)) {
                        getter = method;
                        getterType = methodType;
                    } else {
                        throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
                    }
                }
                addGetMethod(propName, getter);
            }
        }
    }

    private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
        for (String propName : conflictingSetters.keySet()) {
            List<Method> setters = conflictingSetters.get(propName);
            Method firstMethod = setters.get(0);
            if (setters.size() == 1) {
                addSetMethod(propName, firstMethod);
            } else {
                Class<?> expectedType = getTypes.get(propName);
                if (expectedType == null) {
                    throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
                } else {
                    Iterator<Method> methods = setters.iterator();
                    Method setter = null;
                    while (methods.hasNext()) {
                        Method method = methods.next();
                        if (method.getParameterTypes().length == 1 && expectedType.equals(method.getParameterTypes()[0])) {
                            setter = method;
                            break;
                        }
                    }
                    if (setter == null) {
                        throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
                    }
                    addSetMethod(propName, setter);
                }
            }
        }
    }

    private boolean isValidPropertyName(String name) {
        return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
    }

    private void addSetMethod(String name, Method method) {
        if (isValidPropertyName(name)) {
            setMethods.put(name, new MethodInvoker(method));
            setTypes.put(name, method.getParameterTypes()[0]);
        }
    }

    private void addGetMethod(String name, Method method) {
        if (isValidPropertyName(name)) {
            getMethods.put(name, new MethodInvoker(method));
            getTypes.put(name, method.getReturnType());
        }
    }

    private void addSetField(Field field) {
        if (isValidPropertyName(field.getName())) {
            setMethods.put(field.getName(), new SetFieldInvoker(field));
            setTypes.put(field.getName(), field.getType());
        }
    }

    private void addGetField(Field field) {
        if (isValidPropertyName(field.getName())) {
            getMethods.put(field.getName(), new GetFieldInvoker(field));
            getTypes.put(field.getName(), field.getType());
        }
    }

    private Method[] getClassMethods(Class<?> clazz) {
        Map<String, Method> uniqueMethods = new HashMap<>(16);
        Class<?> currentClass = clazz;
        while (currentClass != null) {
            addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

            // 循环判断类是否是抽象类
            Class<?>[] interfaces = currentClass.getInterfaces();
            for (Class<?> anInterface : interfaces) {
                addUniqueMethods(uniqueMethods, anInterface.getDeclaredMethods());
            }

            currentClass = currentClass.getSuperclass();
        }

        Collection<Method> methods = uniqueMethods.values();

        return methods.toArray(new Method[0]);
    }

    private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
        for (Method currentMethod : methods) {
            if (!currentMethod.isBridge()) {
                // 取得签名
                String signature = getSignature(currentMethod);
                // check to see if the method is already known
                // if it is known, then an extended class must have
                // overridden a method
                if (!uniqueMethods.containsKey(signature)) {
                    if (canAccessPrivateMethods()) {
                        try {
                            currentMethod.setAccessible(true);
                        } catch (Exception e) {

                        }
                    }

                    uniqueMethods.put(signature, currentMethod);
                }
            }
        }
    }

    private String getSignature(Method method) {
        StringBuilder sb = new StringBuilder();
        Class<?> returnType = method.getReturnType();
        if (returnType != null) {
            sb.append(returnType.getName()).append("#");
        }
        sb.append(method.getName());
        Class<?>[] parameters = method.getParameterTypes();
        for (int i = 0; i < parameters.length; i++) {
            if (i == 0) {
                sb.append(":");
            } else {
                sb.append(",");
            }
            sb.append(parameters[i].getName());
        }
        return sb.toString();
    }

    private void addMethodConflict(Map<String, List<Method>> conflictingGetters, String name, Method method) {
        List<Method> list = conflictingGetters.computeIfAbsent(name, k -> new ArrayList<>());
        list.add(method);
    }

    public Class<?> getType() {
        return type;
    }

    public Constructor<?> getDefaultConstructor() {
        if (defaultConstructor != null) {
            return defaultConstructor;
        } else {
            throw new RuntimeException("There is no default constructor for " + type);
        }
    }

    public boolean hasDefaultConstructor() {
        return defaultConstructor != null;
    }

    public Invoker getGetInvoker(String propertyName) {
        Invoker method = getMethods.get(propertyName);
        if (method == null) {
            throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
        }
        return method;
    }

    public Invoker getSetInvoker(String propertyName) {
        Invoker method = setMethods.get(propertyName);
        if (method == null) {
            throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
        }
        return method;
    }

    public Class<?> getSetterType(String propertyName) {
        Class<?> clazz = setTypes.get(propertyName);
        if (clazz == null) {
            throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
        }
        return clazz;
    }

    public Class<?> getGetterType(String propertyName) {
        Class<?> clazz = getTypes.get(propertyName);
        if (clazz == null) {
            throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
        }
        return clazz;
    }

    public String[] getGetablePropertyNames() {
        return readablePropertyNames;
    }

    public String[] getSetablePropertyNames() {
        return writeablePropertyNames;
    }

    public boolean hasSetter(String propertyName) {
        return setMethods.keySet().contains(propertyName);
    }

    public boolean hasGetter(String propertyName) {
        return getMethods.keySet().contains(propertyName);
    }

    public String findPropertyName(String name) {
        return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
    }

    public static Reflector forClass(Class<?> clazz) {
        if (classCacheEnabled) {
            // 对于每个类来说,我们假设它是不会变的,这样可以考虑将这个类的信息(构造函数,getter,setter,字段)加入缓存,以提高速度
            Reflector cached = REFLECTOR_MAP.get(clazz);
            if (cached == null) {
                cached = new Reflector(clazz);
                REFLECTOR_MAP.put(clazz, cached);
            }
            return cached;
        } else {
            return new Reflector(clazz);
        }
    }

    public static boolean isClassCacheEnabled() {
        return classCacheEnabled;
    }

    public static void setClassCacheEnabled(boolean classCacheEnabled) {
        Reflector.classCacheEnabled = classCacheEnabled;
    }
}
  • Reflector 反射器类中提供了各类属性、方法、类型以及构造函数的保存操作。
  • 当调用反射器时会通过构造函数的处理,逐步从对象类中拆解出这些属性信息,便于后续反射使用。

3.6 元类包装反射器

  • Reflector 反射器类提供的是最基础的核心功能,很多方法都是私有的,为了更方便使用,还需要做一层元类的包装。
  • 在元类 MetaClass 提供必要的创建反射器以及使用反射器获取 get/setInvoker 反射方法。

MetaClass.java

package com.lino.mybatis.reflection;

import com.lino.mybatis.reflection.invoker.GetFieldInvoker;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.invoker.MethodInvoker;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

/**
 * @description: 元类
 */
public class MetaClass {

    private Reflector reflector;

    public MetaClass(Class<?> type) {
        this.reflector = Reflector.forClass(type);
    }

    public static MetaClass forClass(Class<?> type) {
        return new MetaClass(type);
    }

    public static boolean isClassCacheEnabled() {
        return Reflector.isClassCacheEnabled();
    }

    public static void setClassCacheEnabled(boolean classCacheEnabled) {
        Reflector.setClassCacheEnabled(classCacheEnabled);
    }

    public MetaClass metaClassForProperty(String name) {
        Class<?> propType = reflector.getGetterType(name);
        return MetaClass.forClass(propType);
    }

    public MetaClass metaClassForProperty(PropertyTokenizer prop) {
        Class<?> propType = getGetterType(prop);
        return MetaClass.forClass(propType);
    }

    private StringBuilder buildProperty(String name, StringBuilder builder) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            String propertyName = reflector.findPropertyName(prop.getName());
            if (propertyName != null) {
                builder.append(propertyName);
                builder.append(".");
                MetaClass metaProp = metaClassForProperty(propertyName);
                metaProp.buildProperty(prop.getChildren(), builder);
            }
        } else {
            String propertyName = reflector.findPropertyName(name);
            if (propertyName != null) {
                builder.append(propertyName);
            }
        }
        return builder;
    }

    public String findProperty(String name) {
        StringBuilder prop = buildProperty(name, new StringBuilder());
        return prop.length() > 0 ? prop.toString() : null;
    }

    public String findProperty(String name, boolean useCameCaseMapping) {
        if (useCameCaseMapping) {
            name = name.replace("_", "");
        }
        return findProperty(name);
    }

    public String[] getGetterNames() {
        return reflector.getGetablePropertyNames();
    }

    public String[] getSetterNames() {
        return reflector.getSetablePropertyNames();
    }

    public Class<?> getSetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaClass metaProp = metaClassForProperty(prop.getName());
            return metaProp.getSetterType(prop.getChildren());
        } else {
            return reflector.getSetterType(prop.getName());
        }
    }

    public Class<?> getGetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaClass metaProp = metaClassForProperty(prop);
            return metaProp.getGetterType(prop.getChildren());
        }
        // 解析集合对象中的类型
        return getGetterType(prop);
    }

    private Class<?> getGetterType(PropertyTokenizer prop) {
        Class<?> type = reflector.getGetterType(prop.getName());
        if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
            Type returnType = getGenericGetterType(prop.getName());
            if (returnType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
                if (actualTypeArguments != null && actualTypeArguments.length == 1) {
                    returnType = actualTypeArguments[0];
                    if (returnType instanceof Class) {
                        type = (Class<?>) returnType;
                    } else if (returnType instanceof ParameterizedType) {
                        type = (Class<?>) ((ParameterizedType) returnType).getRawType();
                    }
                }
            }
        }
        return type;
    }

    private Type getGenericGetterType(String propertyName) {
        try {
            Invoker invoker = reflector.getGetInvoker(propertyName);
            if (invoker instanceof MethodInvoker) {
                Field _method = MethodInvoker.class.getDeclaredField("method");
                _method.setAccessible(true);
                Method method = (Method) _method.get(invoker);
                return method.getGenericReturnType();
            } else if (invoker instanceof GetFieldInvoker) {
                Field _field = GetFieldInvoker.class.getDeclaredField("field");
                _field.setAccessible(true);
                Field field = (Field) _field.get(invoker);
                return field.getGenericType();
            }
        } catch (NoSuchFieldException | IllegalAccessException ignored) {
        }
        return null;
    }

    public boolean hasSetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (reflector.hasSetter(prop.getName())) {
                MetaClass metaProp = metaClassForProperty(prop.getName());
                return metaProp.hasSetter(prop.getChildren());
            } else {
                return false;
            }
        } else {
            return reflector.hasSetter(prop.getName());
        }
    }

    public boolean hasGetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (reflector.hasGetter(prop.getName())) {
                MetaClass metaProp = metaClassForProperty(prop);
                return metaProp.hasGetter(prop.getChildren());
            } else {
                return false;
            }
        } else {
            return reflector.hasGetter(prop.getName());
        }
    }

    public Invoker getGetInvoker(String name) {
        return reflector.getGetInvoker(name);
    }

    public Invoker getSetInvoker(String name) {
        return reflector.getSetInvoker(name);
    }

    public boolean hasDefaultConstructor() {
        return reflector.hasDefaultConstructor();
    }
}
  • MetaClass 元类相当于是对我们需要处理对象的包装,解耦一个原对象,包装出一个元类、对象包装器以及对象工厂等,再组合出一个元对象。
  • 相当于说这些元类和元对象都是对我们需要操作的原对象解耦后的封装。有了这样的操作,就可以让我们处理每一个属性或者方法。

3.7 对象包装器 Wrapper

  • 对象包装器相当于是更加进一步反射调用包装处理,同时也为不同的对象类型提供不同的包装策略。
  • 再对象包装器接口中定义了更加明确的需要使用的方法,包括定义出 get/set 标准的通用方法、获取 get/set 属性名称和属性类型,以及添加属性等。

3.7.1 对象包装器接口

ObjectWrapper.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.List;

/**
 * @description: 对象包装器
 */
public interface ObjectWrapper {

    /**
     * get获取
     *
     * @param prop 属性分解标记
     * @return Object
     */
    Object get(PropertyTokenizer prop);

    /**
     * set设置
     *
     * @param prop  属性分解标记
     * @param value 值
     */
    void set(PropertyTokenizer prop, Object value);

    /**
     * 查找属性
     *
     * @param name               属性名称
     * @param useCameCaseMapping 是否使用强制映射
     * @return 属性
     */
    String findProperty(String name, boolean useCameCaseMapping);

    /**
     * 取得getter的名字列表
     *
     * @return getter的名字列表
     */
    String[] getGetterNames();

    /**
     * 取得setter的名字列表
     *
     * @return setter的名字列表
     */
    String[] getSetterNames();

    /**
     * 取得setter的类型
     *
     * @param name 属性名称
     * @return setter的类型
     */
    Class<?> getSetterType(String name);

    /**
     * 取得getter的类型
     *
     * @param name 属性名称
     * @return getter的类型
     */
    Class<?> getGetterType(String name);

    /**
     * 是否有指定的setter
     *
     * @param name 属性名
     * @return 是否有指定的setter
     */
    boolean hasSetter(String name);

    /**
     * 是否有指定的getter
     *
     * @param name 属性名
     * @return 是否有指定的getter
     */
    boolean hasGetter(String name);

    /**
     * 实例化属性
     *
     * @param name          属性名
     * @param prop          属性分解标记
     * @param objectFactory 对象工厂接口
     * @return 元对象
     */
    MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

    /**
     * 是否是集合
     *
     * @return boolean
     */
    boolean isCollection();

    /**
     * 添加属性
     *
     * @param element 属性对象
     */
    void add(Object element);

    /**
     * 添加属性集合
     *
     * @param elements 属性对象集合
     * @param <E>      属性泛型
     */
    <E> void addAll(List<E> elements);
}
  • 后续所有实现了对象包装器接口的实现类,都需要提供这些方法实现,基本有了这些方法,也就能非常容易的处理一个对象的反射操作。
  • 方法:设置属性、获取属性、获取字段列表,获取字段类型

3.7.2 对象包装器抽象基类

BaseWrapper.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.property.PropertyTokenizer;

import java.util.List;
import java.util.Map;

/**
 * @description: 对象包装器抽象基类,提供一些工具方法
 * @author: lingjian
 * @createDate: 2022/11/9 9:55
 */
public abstract class BaseWrapper implements ObjectWrapper {

    protected static final Object[] NO_ARGUMENTS = new Object[0];
    protected MetaObject metaObject;

    public BaseWrapper(MetaObject metaObject) {
        this.metaObject = metaObject;
    }

    /**
     * 解析集合
     *
     * @param prop   属性分解标记
     * @param object 对象
     * @return Object 对象
     */
    protected Object resolveCollection(PropertyTokenizer prop, Object object) {
        if ("".equals(prop.getName())) {
            return object;
        } else {
            return metaObject.getValue(prop.getName());
        }
    }

    /**
     * 取集合的值
     *
     * @param prop       属性分解标记
     * @param collection 对象{Map,List/Array}
     * @return Object 属性对象
     */
    protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
        if (collection instanceof Map) {
            // map['name']
            return ((Map) collection).get(prop.getIndex());
        } else {
            int i = Integer.parseInt(prop.getIndex());
            if (collection instanceof List) {
                // list[0]
                return ((List) collection).get(i);
            } else if (collection instanceof Object[]) {
                return ((Object[]) collection)[i];
            } else if (collection instanceof char[]) {
                return ((char[]) collection)[i];
            } else if (collection instanceof boolean[]) {
                return ((boolean[]) collection)[i];
            } else if (collection instanceof byte[]) {
                return ((byte[]) collection)[i];
            } else if (collection instanceof double[]) {
                return ((double[]) collection)[i];
            } else if (collection instanceof float[]) {
                return ((float[]) collection)[i];
            } else if (collection instanceof int[]) {
                return ((int[]) collection)[i];
            } else if (collection instanceof long[]) {
                return ((long[]) collection)[i];
            } else if (collection instanceof short[]) {
                return ((short[]) collection)[i];
            } else {
                throw new RuntimeException("The '" + prop.getName() + "' property of " + collection + "is not a List or Array.");
            }
        }
    }

    /**
     * 设置集合的值
     *
     * @param prop       属性分解标记
     * @param collection 对象{Map,List/Array}
     * @param value      值
     */
    protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
        if (collection instanceof Map) {
            // map['name']
            ((Map) collection).put(prop.getIndex(), value);
        } else {
            int i = Integer.parseInt(prop.getIndex());
            if (collection instanceof List) {
                ((List) collection).set(i, value);
            } else if (collection instanceof Object[]) {
                ((Object[]) collection)[i] = value;
            } else if (collection instanceof char[]) {
                ((char[]) collection)[i] = (Character) value;
            } else if (collection instanceof boolean[]) {
                ((boolean[]) collection)[i] = (Boolean) value;
            } else if (collection instanceof byte[]) {
                ((byte[]) collection)[i] = (Byte) value;
            } else if (collection instanceof double[]) {
                ((double[]) collection)[i] = (Double) value;
            } else if (collection instanceof float[]) {
                ((float[]) collection)[i] = (Float) value;
            } else if (collection instanceof int[]) {
                ((int[]) collection)[i] = (Integer) value;
            } else if (collection instanceof long[]) {
                ((long[]) collection)[i] = (Long) value;
            } else if (collection instanceof short[]) {
                ((short[]) collection)[i] = (Short) value;
            } else {
                throw new RuntimeException("The '" + prop.getName() + "' property of " + collection + "is not a List or Array.");
            }
        }
    }
}

3.7.3 Bean 包装器

BeanWrapper.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaClass;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.List;

/**
 * @description: Bean 包装器
 */
public class BeanWrapper extends BaseWrapper {

    /**
     * 原来的对象
     */
    private Object object;
    /**
     * 元类
     */
    private MetaClass metaClass;

    public BeanWrapper(MetaObject metaObject, Object object) {
        super(metaObject);
        this.object = object;
        this.metaClass = MetaClass.forClass(object.getClass());

    }

    @Override
    public Object get(PropertyTokenizer prop) {
        // 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValue
        if (prop.getIndex() != null) {
            Object collection = resolveCollection(prop, object);
            return getCollectionValue(prop, collection);
        } else {
            // 否则 getBeanProperty
            return getBeanProperty(prop, object);
        }
    }

    private Object getBeanProperty(PropertyTokenizer prop, Object object) {
        try {
            // 得到getter方法,然后调用
            Invoker method = metaClass.getGetInvoker(prop.getName());
            return method.invoke(object, NO_ARGUMENTS);
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable t) {
            throw new RuntimeException("Count not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t, t);
        }
    }

    @Override
    public void set(PropertyTokenizer prop, Object value) {
        // 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValue
        if (prop.getIndex() != null) {
            Object collection = resolveCollection(prop, object);
            setCollectionValue(prop, collection, value);
        } else {
            // 否则 setBeanProperty
            setBeanProperty(prop, object, value);
        }
    }

    private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
        try {
            // 得到getter方法,然后调用
            Invoker method = metaClass.getSetInvoker(prop.getName());
            Object[] params = {value};
            method.invoke(object, params);
        } catch (Throwable t) {
            throw new RuntimeException("Count not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t, t);
        }
    }

    @Override
    public String findProperty(String name, boolean useCameCaseMapping) {
        return metaClass.findProperty(name, useCameCaseMapping);
    }

    @Override
    public String[] getGetterNames() {
        return metaClass.getGetterNames();
    }

    @Override
    public String[] getSetterNames() {
        return metaClass.getSetterNames();
    }

    @Override
    public Class<?> getSetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return metaClass.getSetterType(name);
            } else {
                return metaValue.getSetterType(prop.getChildren());
            }
        } else {
            return metaClass.getSetterType(name);
        }
    }

    @Override
    public Class<?> getGetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return metaClass.getGetterType(name);
            } else {
                return metaValue.getGetterType(prop.getChildren());
            }
        } else {
            return metaClass.getGetterType(name);
        }
    }

    @Override
    public boolean hasSetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (metaObject.hasSetter(prop.getIndexedName())) {
                MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
                if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                    return metaClass.hasSetter(name);
                } else {
                    return metaValue.hasSetter(prop.getChildren());
                }
            } else {
                return false;
            }
        } else {
            return metaClass.hasSetter(name);
        }
    }

    @Override
    public boolean hasGetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (metaObject.hasGetter(prop.getIndexedName())) {
                MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
                if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                    return metaClass.hasGetter(name);
                } else {
                    return metaValue.hasGetter(prop.getChildren());
                }
            } else {
                return false;
            }
        } else {
            return metaClass.hasGetter(name);
        }
    }

    @Override
    public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
        MetaObject metaValue;
        Class<?> type = getSetterType(prop.getName());
        try {
            Object newObject = objectFactory.create(type);
            metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());
            set(prop, newObject);
        } catch (Exception e) {
            throw new RuntimeException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on " +
                    "instance of " + type.getName() + ". Cause: " + e, e);
        }
        return metaValue;
    }

    @Override
    public boolean isCollection() {
        return false;
    }

    @Override
    public void add(Object element) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <E> void addAll(List<E> elements) {
        throw new UnsupportedOperationException();
    }
}

3.7.4 Collection 包装器

CollectionWrapper.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.Collection;
import java.util.List;

/**
 * @description: Collection 包装器
 */
public class CollectionWrapper implements ObjectWrapper {

    /**
     * 原始对象
     */
    private Collection<Object> object;

    public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {
        this.object = object;
    }

    @Override
    public Object get(PropertyTokenizer prop) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void set(PropertyTokenizer prop, Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String findProperty(String name, boolean useCameCaseMapping) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String[] getGetterNames() {
        throw new UnsupportedOperationException();
    }

    @Override
    public String[] getSetterNames() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Class<?> getSetterType(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Class<?> getGetterType(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean hasSetter(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean hasGetter(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isCollection() {
        return true;
    }

    @Override
    public void add(Object element) {
        object.add(element);
    }

    @Override
    public <E> void addAll(List<E> elements) {
        object.addAll(elements);
    }
}

3.7.5 MapWrapper 包装器

MapWrapper.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: Map 包装器
 */
public class MapWrapper extends BaseWrapper {

    /**
     * 原始对象
     */
    private Map<String, Object> map;

    public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
        super(metaObject);
        this.map = map;
    }

    @Override
    public Object get(PropertyTokenizer prop) {
        // 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValue
        if (prop.getIndex() != null) {
            Object collection = resolveCollection(prop, map);
            return getCollectionValue(prop, collection);
        } else {
            return map.get(prop.getName());
        }
    }

    @Override
    public void set(PropertyTokenizer prop, Object value) {
        // 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValue
        if (prop.getIndex() != null) {
            Object collection = resolveCollection(prop, map);
            setCollectionValue(prop, collection, value);
        } else {
            // 否则 setBeanProperty
            map.put(prop.getName(), value);
        }
    }

    @Override
    public String findProperty(String name, boolean useCameCaseMapping) {
        return name;
    }

    @Override
    public String[] getGetterNames() {
        return map.keySet().toArray(new String[0]);
    }

    @Override
    public String[] getSetterNames() {
        return map.keySet().toArray(new String[0]);
    }

    @Override
    public Class<?> getSetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return Object.class;
            } else {
                return metaValue.getSetterType(prop.getChildren());
            }
        } else {
            if (map.get(name) != null) {
                return map.get(name).getClass();
            } else {
                return Object.class;
            }
        }
    }

    @Override
    public Class<?> getGetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return Object.class;
            } else {
                return metaValue.getGetterType(prop.getChildren());
            }
        } else {
            if (map.get(name) != null) {
                return map.get(name).getClass();
            } else {
                return Object.class;
            }
        }
    }

    @Override
    public boolean hasSetter(String name) {
        return true;
    }

    @Override
    public boolean hasGetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            if (map.containsKey(prop.getIndexedName())) {
                MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
                if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                    return true;
                } else {
                    return metaValue.hasGetter(prop.getChildren());
                }
            } else {
                return false;
            }
        } else {
            return map.containsKey(prop.getName());
        }
    }

    @Override
    public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
        HashMap<String, Object> map = new HashMap<>(16);
        set(prop, map);
        return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());
    }

    @Override
    public boolean isCollection() {
        return false;
    }

    @Override
    public void add(Object element) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <E> void addAll(List<E> elements) {
        throw new UnsupportedOperationException();
    }
}

3.8 对象包装工厂

  • 通过包装工厂获取包装器

3.8.1 对象包装工厂接口

ObjectWrapperFactory.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;

/**
 * @description: 对象包装工厂
 */
public interface ObjectWrapperFactory {

    /**
     * 判断有没有包装器
     *
     * @param object 对象
     * @return boolean
     */
    boolean hasWrapperFor(Object object);

    /**
     * 获取包装器
     *
     * @param metaObject 元对象
     * @param object     对象
     * @return 包装器
     */
    ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
}

3.8.2 默认对象包装工厂实现类

DefaultObjectWrapperFactory.java

package com.lino.mybatis.reflection.wrapper;

import com.lino.mybatis.reflection.MetaObject;

/**
 * @description: 默认对象包装器
 */
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {

    @Override
    public boolean hasWrapperFor(Object object) {
        return false;
    }

    @Override
    public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
        throw new RuntimeException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
    }
}

3.9 对象工厂

3.9.1 对象工厂接口

ObjectFactory.java

package com.lino.mybatis.reflection.factory;

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

/**
 * @description: 对象工厂接口
 */
public interface ObjectFactory {

    /**
     * 设置属性
     *
     * @param properties 属性配置
     */
    void setProperties(Properties properties);
    /**
     * 生产对象
     *
     * @param type 对象类型
     * @param <T>  泛型
     * @return <T> 泛型对象
     */
    <T> T create(Class<T> type);
    /**
     * 生产对象,使用指定的构造函数和构造函数参数
     *
     * @param type                对象类型
     * @param constructorArgTypes 构造函数
     * @param constructorArgs     构造函数参数
     * @param <T>                 泛型
     * @return <T> 泛型对象
     */
    <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
    /**
     * 返回这个对象是否是集合
     *
     * @param type 对象类型
     * @param <T>  泛型
     * @return 是否是集合
     */
    <T> boolean isCollection(Class<T> type);
}

3.9.2 默认对象工厂实现类

DefaultObjectFactory.java

package com.lino.mybatis.reflection.factory;

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

/**
 * @description: 默认对象工厂,所有的对象都由工厂来生成
 */
public class DefaultObjectFactory implements ObjectFactory, Serializable {

    private static final long serialVersionUID = -8855120656740914948L;

    @Override
    public void setProperties(Properties properties) {

    }

    @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) {
        // 1.解析接口
        Class<?> classToCreate = resolveInterface(type);
        // 2.类实例化
        return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
    }

    private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        try {
            Constructor<T> constructor;
            // 如果没有传入constructor,调用空构造函数,核心是调用 Constructor.newInstance
            if (constructorArgTypes == null || constructorArgs == null) {
                constructor = type.getDeclaredConstructor();
                if (!constructor.isAccessible()) {
                    constructor.setAccessible(true);
                }
                return constructor.newInstance();
            }
            // 如果传入constructor,调用传入的构造函数,核心是调用 Constructor.newInstance
            constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
            if (!constructor.isAccessible()) {
                constructor.setAccessible(true);
            }
            return constructor.newInstance(constructorArgs.toArray(new Object[0]));
        } catch (Exception e) {
            // 如果出错,包装一下,重新抛出自己的异常
            StringBuilder argTypes = new StringBuilder();
            if (constructorArgTypes != null) {
                for (Class<?> argType : constructorArgTypes) {
                    argTypes.append(argType.getSimpleName());
                    argTypes.append(",");
                }
            }
            StringBuilder argValues = new StringBuilder();
            if (constructorArgs != null) {
                for (Object argType : constructorArgs) {
                    argValues.append(argType);
                    argTypes.append(",");
                }
            }
            throw new RuntimeException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). " + "Cause: " + e, e);
        }
    }

    /**
     * 解析接口,将 interface 转换为实际的 class类
     *
     * @param type 对象类型
     * @return Class<?> 实现类
     */
    private Class<?> resolveInterface(Class<?> type) {
        Class<?> classToCreate;
        if (type == List.class || type == Collection.class || type == Iterable.class) {
            // List/Collection/Iterable ---> ArrayList
            classToCreate = ArrayList.class;
        } else if (type == Map.class) {
            // Map ---> HashMap
            classToCreate = HashMap.class;
        } else if (type == SortedSet.class) {
            // SortedSet ---> TreeSet
            classToCreate = TreeSet.class;
        } else if (type == Set.class) {
            // Set ---> HashSet
            classToCreate = HashSet.class;
        } else {
            // 除此之外,就用原来的原型
            classToCreate = type;
        }
        return classToCreate;
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
    }
}

3.10 元对象封装

  • 在有了反射器、元类、对象包装器以后,再使用对象工厂和对象包装工厂,就可以组合出一个完整的元对象操作类。
  • 对元对象的管理,包括:包装器策略、包装工程、统一的方法处理。

3.10.1 元对象

MetaObject.java

package com.lino.mybatis.reflection;

import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import com.lino.mybatis.reflection.wrapper.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @description: 元对象
 */
public class MetaObject {

    /**
     * 原始对象
     */
    private Object originalObject;
    /**
     * 对象包装器
     */
    private ObjectWrapper objectWrapper;
    /**
     * 对象工厂
     */
    private ObjectFactory objectFactory;
    /**
     * 对象包装工厂
     */
    private ObjectWrapperFactory objectWrapperFactory;

    public MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
        this.originalObject = object;
        this.objectFactory = objectFactory;
        this.objectWrapperFactory = objectWrapperFactory;

        if (object instanceof ObjectWrapper) {
            // 如果对象本身已经是ObjectWrapper类型,则直接赋给objectWrapper
            this.objectWrapper = (ObjectWrapper) object;
        } else if (objectWrapperFactory.hasWrapperFor(object)) {
            // 如果有包装器,调用objectWrapperFactory.getWrapperFor
            this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
        } else if (object instanceof Map) {
            // 如果是Map类型,返回MapWrapper
            this.objectWrapper = new MapWrapper(this, (Map) object);
        } else if (object instanceof Collection) {
            // 如果是Collection类型,返回CollectionWrapper
            this.objectWrapper = new CollectionWrapper(this, (Collection) object);
        } else {
            // 除此之外,返回 BeanWrapper
            this.objectWrapper = new BeanWrapper(this, object);
        }
    }

    /**
     * 返回元对象
     *
     * @param object               原始对象
     * @param objectFactory        对象工厂
     * @param objectWrapperFactory 对象包装工厂
     * @return MetaObject 元对象
     */
    public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
        if (object == null) {
            // 处理一下null,将null包装起来
            return SystemMetaObject.NULL_META_OBJECT;
        } else {
            return new MetaObject(object, objectFactory, objectWrapperFactory);
        }
    }

    public Object getOriginalObject() {
        return originalObject;
    }

    public ObjectWrapper getObjectWrapper() {
        return objectWrapper;
    }

    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }

    public ObjectWrapperFactory getObjectWrapperFactory() {
        return objectWrapperFactory;
    }

    /* 以下属性委派给 ObjectWrapper */

    /**
     * 查找属性
     */
    public String findProperty(String propName, boolean useCameCaseNapping) {
        return objectWrapper.findProperty(propName, useCameCaseNapping);
    }

    /**
     * 取得getter的名字列表
     */
    public String[] getGetterNames() {
        return objectWrapper.getGetterNames();
    }

    /**
     * 取得setter的名字列表
     */
    public String[] getSetterNames() {
        return objectWrapper.getSetterNames();
    }

    /**
     * 取得setter的类型
     */
    public Class<?> getSetterType(String children) {
        return objectWrapper.getSetterType(children);
    }

    /**
     * 取得getter的类型
     */
    public Class<?> getGetterType(String children) {
        return objectWrapper.getGetterType(children);
    }

    /**
     * 是否有指定的setter
     */
    public boolean hasSetter(String indexedName) {
        return objectWrapper.hasSetter(indexedName);
    }

    /**
     * 是否有指定的getter
     */
    public boolean hasGetter(String children) {
        return objectWrapper.hasGetter(children);
    }

    /**
     * 是否是集合
     */
    public boolean isCollection() {
        return objectWrapper.isCollection();
    }

    /**
     * 添加属性
     */
    public void add(Object element) {
        objectWrapper.add(element);
    }

    /**
     * 添加属性集合
     */
    public <E> void addAll(List<E> elements) {
        objectWrapper.addAll(elements);
    }

    /**
     * 获取值
     *
     * @param name 属性名称
     * @return 值
     */
    public Object getValue(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                // 如果上层是null,那就结束,返回null
                return null;
            } else {
                // 否则继续看下一层,递归调用getValue
                return metaValue.getValue(prop.getChildren());
            }
        } else {
            return objectWrapper.get(prop);
        }
    }

    /**
     * 设置值
     *
     * @param name  属性名
     * @param value 属性值
     */
    public void setValue(String name, Object value) {
        PropertyTokenizer prop = new PropertyTokenizer(name);
        if (prop.hasNext()) {
            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                if (value == null && prop.getChildren() != null) {
                    // 如果上层是null,还得看有没有子对象,没有就结束
                    return;
                } else {
                    // 否则还得 new 一个,委派给 objectWrapper.instantiatePropertyValue
                    metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
                }
            }
            // 递归调用setValue
            metaValue.setValue(prop.getChildren(), value);
        } else {
            // 到最后层了,所以委派给 objectWrapper.set
            objectWrapper.set(prop, value);
        }
    }

    /**
     * 为属性生成元对象
     *
     * @param name 属性名
     * @return 元对象
     */
    public MetaObject metaObjectForProperty(String name) {
        // 递归调用
        Object value = getValue(name);
        return MetaObject.forObject(value, objectFactory, objectWrapperFactory);
    }

}
  • MetaObject 元对象算是整个服务的包装,在构造函数中提供各类对象的包装器类型的创建。
    • 包括这里提供的 getValue(String name)、setValue(String name, Object value) 等。
    • 其中当一些对象中的属性信息不是一个层次,班级[0].学生.成绩 需要被拆解后才能获取到对应的对象和属性值。

3.10.2 系统级别元对象

SystemMetaObject.java

package com.lino.mybatis.reflection;

import com.lino.mybatis.reflection.factory.DefaultObjectFactory;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory;
import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory;

/**
 * @description: 系统级别元对象
 */
public class SystemMetaObject {

    public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(NullObject.class, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);

    private SystemMetaObject() {
    }

    private static class NullObject {
    }

    public static MetaObject forObject(Object object) {
        return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
    }
}
  • 使用 SystemMetaObject#forObject 提供元对象的获取。

3.11 数据源属性设置

  • 现在有了我们实现的属性反射操作工具包,那么对于数据源中属性信息的设置,就可以使用反射来设置和获取。

3.11.1 无池化数据源工厂

UnpooledDataSourceFactory.java

package com.lino.mybatis.datasource.unpooled;

import com.lino.mybatis.datasource.DataSourceFactory;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * @description: 无池化数据源工厂
 */
public class UnpooledDataSourceFactory implements DataSourceFactory {

    protected DataSource dataSource;

    public UnpooledDataSourceFactory() {
        this.dataSource = new UnpooledDataSource();
    }

    @Override
    public void setProperties(Properties props) {
        MetaObject metaObject = SystemMetaObject.forObject(dataSource);
        for (Object key : props.keySet()) {
            String propertyName = (String) key;
            if (metaObject.hasSetter(propertyName)) {
                String value = (String) props.get(propertyName);
                Object convertedValue = convertValue(metaObject, propertyName, value);
                metaObject.setValue(propertyName, convertedValue);
            }
        }
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 根据setter的类型,将配置文件中的值强转成相应的类型
     *
     * @param metaObject   元对象
     * @param propertyName 属性名
     * @param value        属性值
     * @return Object 转化后的对象
     */
    private Object convertValue(MetaObject metaObject, String propertyName, String value) {
        Object convertedValue = value;
        Class<?> targetType = metaObject.getSetterType(propertyName);
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        return convertedValue;
    }
}
  • setProperties 方法中使用 SystemMetaObject.forObject(dataSource) 获取 DataSource 的元对象,也就是通过反射设置属性值。

3.11.2 有池化数据源工厂

PooledDataSourceFactory.java

package com.lino.mybatis.datasource.pooled;

import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import javax.sql.DataSource;

/**
 * @description: 有连接池的数据源工厂
 */
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

    public PooledDataSourceFactory() {
        this.dataSource = new PooledDataSource();
    }
}
  • 设置属性:继承无池化数据源工厂的属性设置。

四、测试:元对象反射类

4.1 单元测试

ApiTest.java

@Test
public void test_SqlSessionFactoryExecutor() throws IOException {
    // 1.从SqlSessionFactory中获取SqlSession
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 2.获取映射器对象
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);

    // 3.测试验证
    User user = userDao.queryUserInfoById(1L);
    logger.info("测试结果:{}", JSON.toJSONString(user));
}

测试结果

09:17:52.915 [main] INFO  c.l.m.d.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
09:17:53.782 [main] INFO  c.l.m.d.pooled.PooledDataSource - Created connention 2104028992.
09:17:53.891 [main] INFO  com.lino.mybatis.test.ApiTest - 测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小灵哥"}

在这里插入图片描述

  • 根据单元测试和调试的截图,可以看到属性值通过反射的方式设置到对象中,满足了我们在创建数据源时的使用。

4.2 反射类测试

4.2.1 学生实体类

Student.java

package com.lino.mybatis.test.po;

/**
 * @description: 学生类
 */
public class Student {

    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

4.2.2 老师实体类

Teacher.java

package com.lino.mybatis.test.po;

import java.util.List;

/**
 * @description: 教师类
 */
public class Teacher {

    private String name;

    private double price;

    private List<Student> students;

    private Student student;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }
}

4.2.3 反射类测试

ReflectorTest.java

package com.lino.mybatis.test;

import com.alibaba.fastjson.JSON;
import com.lino.mybatis.io.Resources;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.session.SqlSession;
import com.lino.mybatis.session.SqlSessionFactory;
import com.lino.mybatis.session.SqlSessionFactoryBuilder;
import com.lino.mybatis.test.dao.IUserDao;
import com.lino.mybatis.test.po.Student;
import com.lino.mybatis.test.po.Teacher;
import com.lino.mybatis.test.po.User;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: 反射测试
 */
public class ReflectionTest {

    private Logger logger = LoggerFactory.getLogger(ReflectionTest.class);

    @Test
    public void test_reflection() {
        Teacher teacher = new Teacher();
        List<Student> list = new ArrayList<>();
        list.add(new Student());
        teacher.setName("小零哥");
        teacher.setStudents(list);

        MetaObject metaObject = SystemMetaObject.forObject(teacher);

        logger.info("getGetterNames:{}", JSON.toJSONString(metaObject.getGetterNames()));
        logger.info("getSetterNames:{}", JSON.toJSONString(metaObject.getSetterNames()));
        logger.info("name的get方法返回值:{}", JSON.toJSONString(metaObject.getGetterType("name")));
        logger.info("students的set方法参数值:{}", JSON.toJSONString(metaObject.getGetterType("students")));
        logger.info("name的hasGetter:{}", metaObject.hasGetter("name"));
        logger.info("student.id(属性为对象)的hasGetter:{}", metaObject.hasGetter("student.id"));
        logger.info("获取name的属性值:{}", metaObject.getValue("name"));
        // 重新设置属性值
        metaObject.setValue("name", "哆啦A梦");
        logger.info("设置name的属性值:{}", metaObject.getValue("name"));
        // 设置属性(集合)的元素值
        metaObject.setValue("students[0].id", "001");
        logger.info("获取students集合的第一个元素的属性值:{}", JSON.toJSONString(metaObject.getValue("students[0].id")));
        logger.info("对象的序列化:{}", JSON.toJSONString(teacher));
    }
}

测试结果

09:23:10.154 [main] INFO  com.lino.mybatis.test.ReflectionTest - getGetterNames:["student","price","name","students"]
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - getSetterNames:["student","price","name","students"]
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - name的get方法返回值:"java.lang.String"
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - students的set方法参数值:"java.util.List"
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - name的hasGetter:true
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - student.id(属性为对象)的hasGetter:true
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 获取name的属性值:小零哥
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 设置name的属性值:哆啦A09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 获取students集合的第一个元素的属性值:"001"
09:23:10.192 [main] INFO  com.lino.mybatis.test.ReflectionTest - 对象的序列化:{"name":"哆啦A梦","price":0.0,"students":[{"id":"001"}]}
  • 从测试结果看,我们拿到了对于的属性信息,并可以设置以及修改属性值,无论是单个属性还是对象属性,都可以操作。

五、总结:元对象反射类

  • 关于反射工具类的实现中,使用了大量的 JDK 所提供的关于反射一些操作,也包括可以获取一个 Class 类中的属性、字段、方法的信息。
  • 有了这些信息以后就可以按照功能流程进行解耦,把属性、反射、包装,都依次拆分出来,并按照设计原则,逐步包装让外界更少的知道内部的处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/99468.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8超参数调优教程! 使用Ray Tune进行高效的超参数调优!

原创文章为博主个人所有,未经授权不得转载、摘编、倒卖、洗稿或利用其它方式使用上述作品。违反上述声明者,本站将追求其相关法律责任。 这篇博文带大家玩点新的东西,也是一直以来困扰大家最大的问题—超参数调优! 之前的 YOLOv5 我使用遗传算法做过很多次调优,实验一跑就…

git 基础入门

Git基础入门 Git是一个分布式 版本管理系统&#xff0c;用于跟踪文件的变化和协同开发。 版本管理&#xff1a;理解成档案馆&#xff0c;记录开发阶段各个版本 分布式&集中式 分布式每个人都有一个档案馆&#xff0c;集中式只有一个档案馆。分布式每人可以管理自己的档案…

一文速学-让神经网络不再神秘,一天速学神经网络基础-前向传播(三)

前言 思索了很久到底要不要出深度学习内容&#xff0c;毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新&#xff0c;很多坑都没有填满&#xff0c;而且现在深度学习的文章和学习课程都十分的多&#xff0c;我考虑了很久决定还是得出神经网络系列文章&#xff0c;…

——滑动窗口

滑动窗口 所谓滑动窗口&#xff0c;就是不断的调节子序列的起始位置和终止位置&#xff0c;从而得出我们要想的结果。也可以理解为一种双指针的做法。 leetcode76 class Solution {public String minWindow(String s, String t) {char[] schars s.toCharArray();char[] tc…

服务器部署前后端项目-SQL Father为例

hello~大家好哇&#xff0c;好久没更新博客了。现在来更新一波hhh 现在更新一下部署上的一些东西&#xff0c;因为其实有很多小伙伴跟我之前一样&#xff0c;很多时候只是开发了&#xff0c;本地前后端都能调通&#xff0c;也能用&#xff0c;但是没有部署到服务器试过&#x…

如果你觉得自己很失败,请观看此内容 视频学习

目录 什么是成功&#xff1f;​​​​​​​ How can we succeed in such an unfair world? 我们如何在这个不公平的地球上获得成功&#xff1f; 如何去找到自己的不公平优势呢&#xff1f; 最开始也有常有人跟她说你做视频是赚不到钱的 你做了&#xff0c;并不代表你做…

Spring版本与JDK版本演变

Java各版本变更核心API Java8 lambada表达式函数式接口方法引用默认方法Stream API 对元素流进行函数式操作Optional 解决NullPointerExceptionDate Time API重复注解 RepeatableBase64使用元空间Metaspace代替持久代&#xff08;PermGen space&#xff09; Java7 switch 支…

day3 c++d对话框及事件处理机制

1.文本编辑器 2.自由移动的球

手把手教你写出第一个C语言程序

Hello, World! 1. 前言2. 准备知识2.1 环境2.2 文件的分类2.3 注释2.3.1 注释的作用2.3.2 注释的两种风格2.3.2.1 C语言的注释风格2.3.2.2 C的注释风格 2.3.3 VS中注释和取消注释的快捷键 3. 开始演示3.1 创建项目3.2 创建源文件3.3 写代码3.4 编译链接运行 4. 代码解释4.1 写主…

QT DAY4

一、对话框 消息对话框、字体对话框、颜色对话框、文件对话框 1.1消息对话框 主要分为这四类对话及一种NoIcon无图标对话 而对话框也分为两种实现方式&#xff0c;一种为基于属性分开初始化的方式&#xff0c;这种方式更灵活&#xff0c;更多元&#xff0c;需要对exec的返回值…

SQLPro Studio for Mac:强大的SQL开发和管理工具

SQLPro Studio for Mac是一款强大的Mac上使用的SQL开发和管理工具&#xff0c;它支持各种数据库&#xff0c;包括MySQL&#xff0c;PostgreSQL&#xff0c;SQLite等。使用 SQLPro Studio&#xff0c;您可以轻松地连接和管理您的数据库&#xff0c;执行SQL查询和脚本&#xff0c…

c++11 标准模板(STL)(std::basic_ostringstream)(一)

定义于头文件 <sstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ostringstream;(C11 前)template< class CharT, class Traits std::char_traits<CharT>, class Allocator std::allo…

Windows安装Nginx及部署vue前端项目操作

先在nginx官网下载windows下安装的包&#xff0c;并解压&#xff0c;到ngnix目录下 双击nginx.exe,会有黑窗闪过。 用cmd命令窗口&#xff0c;cd 到nginx解压目录&#xff0c;./nginx启动。 在浏览器中访问http://localhost:80,出现以下界面说明启动成功(由于笔者电脑80端口被…

【核心复现】基于改进灰狼算法的并网交流微电网经济优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Nano编辑器安装使用指南

关于nano Nano编辑器是一个命令行文本编辑器&#xff0c;具有简单易用的界面和一些基本功能。 Nano小巧友好&#xff0c;提供许多额外的特性&#xff0c;例如交互式的查找和替换、定位到指定的行列、自动缩进、特性切换、国际化支持、文件名标记完成等。 Nano是为了代替闭源的…

【0901作业】QTday3 对话框、发布软件、事件处理机制,使用文件相关操作完成记事本的保存功能、处理键盘事件完成圆形的移动

目录 一、思维导图 二、作业 2.1 使用文件相关操作完成记事本的保存功能 2.2 处理键盘事件完成圆形的移动 一、思维导图 二、作业 2.1 使用文件相关操作完成记事本的保存功能 void Widget::on_saveBtn_clicked() {QString filename QFileDialog::getSaveFileName(this,&…

DVWA失效的访问控制

失效的访问控制&#xff0c;可以认为是系统对一些功能进行了访问或权限限制&#xff0c;但因为种种原因&#xff0c;限制并没有生效&#xff0c;造成失效的访问控制漏洞,比如越权等 这里以DVWA为例&#xff0c;先访问低难度的命令执行并抓包 删除cookie&#xff0c;并在请求头…

堆的基本存储(Java 实例代码)

堆的基本存储 一、概念及其介绍 堆(Heap)是计算机科学中一类特殊的数据结构的统称。 堆通常是一个可以被看做一棵完全二叉树的数组对象。 堆满足下列性质&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值。堆总是一棵完全二叉树。 二、适用说明 堆是利用完…

【防火墙】防火墙NAT Server的配置

Web举例&#xff1a;公网用户通过NAT Server访问内部服务器 介绍公网用户通过NAT Server访问内部服务器的配置举例。 组网需求 某公司在网络边界处部署了FW作为安全网关。为了使私网Web服务器和FTP服务器能够对外提供服务&#xff0c;需要在FW上配置NAT Server功能。除了公网…

java八股文面试[多线程]——进程与线程的区别

定义 1、进程&#xff1a;进程是一个具有独立功能的程序关于某个数据集合的以此运行活动。 是系统进行资源分配和调度的独立单位&#xff0c;也是基本的执行单元。是一个动态的概念&#xff0c;是一个活动的实体。它不只是程序的代码&#xff0c;还包括当前的活动。 进程结构…