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

news2024/11/20 4:30:27

文章目录

  • 一、目标:元对象反射类
  • 二、设计:元对象反射类
  • 三、实现:元对象反射类
    • 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 类中的属性、字段、方法的信息。
  • 有了这些信息以后就可以按照功能流程进行解耦,把属性、反射、包装,都依次拆分出来,并按照设计原则,逐步包装让外界更少的知道内部的处理。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Modbus TCP通信笔记

目录 1 Modbus TCP 数据协议1.1 数据格式1.2 报文头(MBAP头)1.3 功能码1.4 Modbus 地址映射到 CPU 地址 2 Modbus TCP 通讯数据示例2.1 功能码01 读离散输出线圈2.2 功能码02 读离散输入线圈2.3 功能码03 读保持寄存器2.4 功能码04 读输入寄存器2.5 功能码05 写单个离散输出寄存…

DevOps理念:开发与运维的融合

在现代软件开发领域&#xff0c;DevOps 不仅仅是一个流行的词汇&#xff0c;更是一种文化、一种哲学和一种方法论。DevOps 的核心理念是通过开发和运维之间的紧密合作&#xff0c;实现快速交付、高质量和持续创新。本文将深入探讨 DevOps 文化的重要性、原则以及如何在团队中实…

用Rust打印hello world!

步骤1 桌面新建1个名为 rustDemo 的文件夹&#xff08;文件夹名字随便取&#xff09; 步骤2 打开新建的文件夹&#xff0c;在地址输入栏输入 cmd 按回车键进入命令行窗口 步骤3 打开编译器&#xff0c;按 Ctrl S&#xff0c;保存文件到 rustDemo 文件夹中&#xff0c;保存的…

C++算法 —— 分治(1)快排

文章目录 1、颜色分类2、排序数组3、第k个最大的元素&#xff08;快速选择&#xff09;4、最小的k个数&#xff08;快速选择&#xff09; 分治&#xff0c;就是分而治之&#xff0c;把大问题划分成多个小问题&#xff0c;小问题再划分成更小的问题。像快排和归并排序就是分治思…

Linux网络编程 网络基础知识

目录 1.网络的历史和协议的分成 2.网络互联促成了TCP/IP协议的产生 3.网络的体系结构 4.TCP/IP协议族体系 5.网络各层的协议解释 6.网络的封包和拆包 7.网络预备知识 1.网络的历史和协议的分成 Internet-"冷战"的产物 1957年十月和十一月&#xff0c;前苏…

centOS下载与安装

1 下载centOS镜像 The CentOS Project 选择阿里云的镜像 2 下载虚拟机 Vmware workstation VMware - Delivering a Digital Foundation For Businesses 1 下载安装 centOs是一个操作系统&#xff0c;操作硬件的。所以需要有机器&#xff0c;可以使用虚拟机。 2 创建新的虚…

org.mockito:mockito-core 组件安全漏洞及健康度分析

组件简介 维护者mockito组织许可证类型MIT首次发布2008 年 4 月 29 日最新发布时间2023 年 8 月 27 日GitHub Star14159GitHub Fork2478依赖包24,748依赖存储库145,258 org.mockito:mockito-core是一个流行的 Java 模拟框架&#xff0c;它提供了一个简洁的 API 来创建和使用模拟…

【笔记】常用 js 函数

数组去重 Array.from(new Set()) 对象合并 Object.assign . 这里有个细节&#xff1a;当两个对象中含有key相同value不同时&#xff0c;会以 后面对象的key&#xff1a;value为准 保留小数点后几位 toFixed 注意&#xff1a; Number型&#xff0c;用该方法处理完&#xff0c;会…

Windows右键添加用 VSCODE 打开

1.安装VSCODE时 安装时会有个选项来添加&#xff0c;如下&#xff1a; ①将“通过code 打开“操作添加到windows资源管理器文件上下文菜单 ②将“通过code 打开”操作添加到windows资源管理器目录上下文菜单 说明&#xff1a;①②勾选上&#xff0c;可以对文件&#xff0c;目…

O2OA(翱途)开发平台 V8.1正式发布

尊敬的O2OA(翱途)平台合作伙伴、用户以及亲爱的开发小伙伴们&#xff0c;平台 V8.1版本已正式发布。正值8月的最后一周&#xff0c;我们以更安全、更高效、更好用的崭新面貌迎接9月的到来。 O2OA开发平台v8.1版本更注重于对系统级别的安全防护。其中重大的更新&#xff0c;是对…

Re44:数据集 GSM8K 和 论文 Training Verifiers to Solve Math Word Problems

诸神缄默不语-个人CSDN博文目录 论文全名&#xff1a;Training Verifiers to Solve Math Word Problems GSM8K数据集原始论文 OpenAI 2021年的工作&#xff0c;关注解决MWP问题&#xff08;具体场景是小学&#xff08;grade school&#xff09;数学题&#xff09;&#xff0c…

Java设计模式:四、行为型模式-09:模板模式

文章目录 一、定义&#xff1a;模板模式二、模拟场景&#xff1a;模板模式三、改善代码&#xff1a;模板模式3.0 引入依赖3.1 工程结构3.2 模板模式结构图3.3 爬取商品生成海报实现3.3.1 HTTP获取连接类3.3.2 定义执行顺序的抽象类3.3.3 当当爬取抽象实现类3.3.4 京东爬取抽象实…

java八股文面试[多线程]——synchronized锁升级详细流程

偏向锁 偏向锁是JDK6中的重要引进&#xff0c;因为HotSpot作者经过研究实践发现&#xff0c;在大多数情况下&#xff0c;锁不仅不存在多线程竞争&#xff0c;而且总是由同一线程多次获得&#xff0c;为了让线程获得锁的代价更低&#xff0c;引进了偏向锁。 偏向锁是在单线程执…

python3.11教程1:python基础语法、程序控制、函数

文章目录 一、Python简介1.1 为什么学习python1.2 python安装与配置1.3 python解释器1.4 命令行参数1.4.1 sys.argv变量1.4.2 -c和-m选项 1.5 解释器的运行环境1.5.1 编码格式1.5.2 编码声明 二、Python基础语法2.1 行结构2.2 变量&#xff08;标识符&#xff09;2.3 字节串2.4…

如何让照片动起来?几步操作轻松动起来

现在&#xff0c;许多人都喜欢在社交媒体上分享自己的照片。但是&#xff0c;有时单张静态照片可能无法完全表达出你想要表达的感觉。为了使你的照片更生动有趣&#xff0c;你可以使用一些简单的技巧使它们动起来。下面是几个简单的步骤。 步骤1&#xff1a;打开制作应用并导入…

图像融合去雾、近红外去雾、(近)红外和可见光数据集

今天给大家分享一篇发表在IEEE TMM上的去雾文章Joint Contrast Enhancement and Exposure Fusion for Real-World Image Dehazing 作者从对比度增强和曝光融合的视角来解决图像去雾问题&#xff0c;在真实场景上取得了较好的去雾效果。此外&#xff0c;作者将所提出的方法应用…

Json解析流程

一、拿到了题库 分析一下可以定义的 1、序号&#xff0c;用来区分题目数&#xff0c;每个题有唯一的序号 2、题目&#xff0c;就是下图的Q 3、预设的回答&#xff0c;下图的A 分析完我可以知道有三个字段&#xff0c;分别是int index、string Q、string A。 二、把字段丢到…

MongoDB 会丢数据吗? 在次补刀MongoDB 双机热备

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis &#xff0c;Oracle ,Oceanbase 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加微信号 liuaustin3 &#xff08;…

git 查看当前分支最近一次提交的commit SHA

获取当前分支最近一次commit SHA &#xff08;长度为40个16进制数字的字符&#xff09;命令如下&#xff1a; git rev-parse HEAD 获取简写&#xff08;短&#xff09; commit SHA git rev-parse --short HEAD

灾备中的网络加密是什么?

什么是网络加密&#xff1f; 在网络设计之初&#xff0c;对网络安全的问题考虑的不周全&#xff0c;数据在链路上传输的时候都是明文传输的&#xff0c;稍微有点技术的人&#xff0c;都可以轻松的拿到网络上的数据流量&#xff0c;并进行查看。试想一下&#xff0c;如果我们为…