历时漫长的岁月,终于鼓起勇气继续研究Mybatis的反射工具类们,简直就是把反射玩出花,但是理解起来还是很有难度的,涉及的内容代码也颇多,所以花费时间也比较浩大,不过当了解套路每个类的功能也好,设计也好,基本也可以浓缩成一句话理解,心中有了系统也好似没有那么难理解了,本节如在工作中使用到此场景,可以拿来当作工具直接使用。

  1. 前言-为什么使用反射

在手敲Mybatis-数据源池化处理实现那一节,我们留下了坑需要填,在获取连接时,数据库连接的设置还是硬编码,如果我们此时xml文件又需要新增加一些属性,就需要进行修改代码,会发现代码设计不太灵活,本节就为了解决此问题,来一起写一个很强大的反射工具类。

  1. UML类图-类关系介绍

MyBatis设计将分为以下几个类,元类、元对象、对象包装器、反射器、调用者、对象工厂,下面就介绍这几个设计都是干什么的:

SystemMetaObject:系统入口,万物的开始,系统级别的元对象

MetaObject:元对象,外部系统调用入口,封装了包装器对象,在构造方法中使用策略模式来调用不同的对象包装器

MetaClass:元类,通过对象包装器进入,此类是对反射器的封装并进一步进行处理某些场景复杂操作

Reflector:反射器,解析对象的属性、方法、类型的解析器,最后组装起来,提供基础的方法获取数据

ObjectWrapper:对象包装器接口,定义对象基本信息

BaseWrapper:基础包装器,抽取共用包装器方法,解析集合获取集合设置集合等处理

BeanWrapper:原生包装器,对bean对象进行处理,由此方法进入MetaClass类最后进入 Reflector反射将对象数据得到。

CollectionWrapper:原生集合包装器

MapWrapper:map集合包装器,处理map对象

ObjectWrapperFactory:对象包装器工厂接口,可以获取对象包装器

DefaultObjectWrapperFactory:实现对象包装器工厂接口

ObjectFactory:对象工厂接口

DefaultObjectFactory:默认对象工厂接口,创建对象实例处理

Invoker: 调用者接口,定义反射调用

MethodInvoker:方法调用者,反射方法的

GetFieldInvoker此类用于执行读取属性值的反射操作

SetFieldInvoker:用于执行设置属性值的反射操作

PropertyNamer:属性命名器,会将方法转换为属性名称

PropertyTokenizer :属性解析器,属性也不只有单一属性也会有复杂属性,例如属性.属性,集合等

执行流程:SystemMetaObject–>MetaObject–>ObjectWrapper–>MetaClass–>Reflector–>Invoker

而属解析器在处理中有时各个类都会用,反射器工具类要用的就这个20个类,想必你通过介绍大大致对它有印象了,可以对应看下uml图理解理解

  1. 完整代码实现

3.1 反射调用者

package df.middleware.mybatis.reflection.invoker

Invoker:反射调用者接口,定义invoke方法,子类具体实现对应的调用者,因为反射调用离不开目标对象和参数,所以此接口统一定义invoke()。

/** * @description 调用者接口 * @date 2022/5/2 * 此接口的作用统一基于反射处理方法和属性的调用方式,采取策略模式 */public interface Invoker {    /**     * 执行反射操作     *     * @param target 方法或者属性执行的目标对象     * @param args   方法或者属性执行时依赖的参数     */    Object invoke(Object target, Object[] args) throws Exception;    /**     *方法或者属性对应的类型     */    Class 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);                }            }        }    }    // 加入set方法以MethodInvoker放入全局变量里    private void addSetMethod(String name, Method method) {        if (isValidPropertyName(name)) {            setMethods.put(name, new MethodInvoker(method));            setTypes.put(name, method.getParameterTypes()[0]);        }    }    private void addFields(Class clazz) {        Field[] fields = clazz.getDeclaredFields();        for (Field field : fields) {            if (canAccessPrivateMethods()) {                try {                    field.setAccessible(true);                } catch (Exception e) {                    // Ignored. This is only a final precaution, nothing we can do.                }            }            if (field.isAccessible()) {                if (!setMethods.containsKey(field.getName())) {                    // issue #379 - removed the check for final because JDK 1.5 allows                    // modification of final fields through reflection (JSR-133). (JGB)                    // pr #16 - final static can only be set by the classloader                    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 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 void resolveGetterConflicts(Map<String, List> conflictingGetters) {        for (String propName : conflictingGetters.keySet()) {            List getters = conflictingGetters.get(propName);            Iterator 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);            }        }    }    // 加入get方法以MethodInvoker放入全局变量里    private void addGetMethod(String name, Method method) {        if (isValidPropertyName(name)) {            getMethods.put(name, new MethodInvoker(method));            getTypes.put(name, method.getReturnType());        }    }    private boolean isValidPropertyName(String name) {        return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));    }    private void addMethodConflict(Map<String, List> conflictingMethods, String name, Method method) {        List list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList());        list.add(method);    }    // 查找当前类及父类方法    private Method[] getClassMethods(Class cls) {        Map uniqueMethods = new HashMap();        Class currentClass = cls;        while (currentClass != null) {            addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());            // we also need to look for interface methods -            // because the class may be abstract            Class[] interfaces = currentClass.getInterfaces();            for (Class anInterface : interfaces) {                addUniqueMethods(uniqueMethods, anInterface.getMethods());            }            currentClass = currentClass.getSuperclass();        }        Collection methods = uniqueMethods.values();        return methods.toArray(new Method[methods.size()]);    }    // 校验方法唯一性,暂存临时集合    private void addUniqueMethods(Map 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) {                            // Ignored. This is only a final precaution, nothing we can do.                        }                    }                    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 static boolean canAccessPrivateMethods() {        try {            SecurityManager securityManager = System.getSecurityManager();            if (null != securityManager) {                securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));            }        } catch (SecurityException e) {            return false;        }        return true;    }    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 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 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;    }    /*     * Gets the type for a property getter     *     * @param propertyName - the name of the property     * @return The Class of the propery getter     */    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;    }    /*     * Gets an array of the readable properties for an object     *     * @return The array     */    public String[] getGetablePropertyNames() {        return readablePropertyNames;    }    /*     * Gets an array of the writeable properties for an object     *     * @return The array     */    public String[] getSetablePropertyNames() {        return writeablePropertyNames;    }    /*     * Check to see if a class has a writeable property by name     *     * @param propertyName - the name of the property to check     * @return True if the object has a writeable property by the name     */    public boolean hasSetter(String propertyName) {        return setMethods.keySet().contains(propertyName);    }    /*     * Check to see if a class has a readable property by name     *     * @param propertyName - the name of the property to check     * @return True if the object has a readable property by the name     */    public boolean hasGetter(String propertyName) {        return getMethods.keySet().contains(propertyName);    }    public String findPropertyName(String name) {        return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));    }    /*     * Gets an instance of ClassInfo for the specified class.     * 得到某个类的反射器,是静态方法,而且要缓存,又要多线程,所以REFLECTOR_MAP是一个ConcurrentHashMap     *     * @param clazz The class for which to lookup the method cache.     * @return The method cache for the class     */    public static Reflector forClass(Class clazz) {        if (classCacheEnabled) {            // synchronized (clazz) removed see issue #461            // 对于每个类来说,我们假设它是不会变的,这样可以考虑将这个类的信息(构造函数,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 void setClassCacheEnabled(boolean classCacheEnabled) {        Reflector.classCacheEnabled = classCacheEnabled;    }    public static boolean isClassCacheEnabled() {        return classCacheEnabled;    }}

3.3 元类

MetaClass:元类,因为反射器都是基础的操作,为了方便使用对反射器的进一步封装,获取反射器里的容器数据,元类里提供反射器缓存,这样不用相同的类每次调用都解析处理了,也是补充丰富了反射器基础的操作,相当于解构一个对象包装一个元类,而这些元类,包装器,对象工厂再组合成一个元对象,相当于说这些元类和元对象都是对我们需要操作的原对象解耦后的封装。有了这样的操作,就可以让我们处理每一个属性或者方法了。

/** * @description 元类 * Reflector 反射器类提供的是最基础的核心功能,很多方法也都是私有的,为了更加方便的使用, * 还需要做一层元类的包装。在元类 MetaClass 提供必要的创建反射器以及使用反射器获取 * get/set 的 Invoker 反射方法 * */public class MetaClass {    // 反射器,用于解析和存储目标类中的元信息    private Reflector reflector;    // Reflector.forClass获取当前类的反射器    private 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 String findProperty(String name) {        StringBuilder prop = buildProperty(name, new StringBuilder());        return prop.length() > 0 ? prop.toString() : null;    }    public String findProperty(String name, boolean useCamelCaseMapping) {        if (useCamelCaseMapping) {            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());        }        // issue #506. Resolve the type inside a Collection Object        return getGetterType(prop);    }    private MetaClass metaClassForProperty(PropertyTokenizer prop) {        Class propType = getGetterType(prop);        return MetaClass.forClass(propType);    }    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);    }    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 boolean hasDefaultConstructor() {        return reflector.hasDefaultConstructor();    }}

3.4 对象包装器

ObjectWapper:对象包装器接口,定义对象基本操作,获取对象值、设置对象值、查找属性、获取get方法、获取set方法、属性类型、添加属性、设置属性等等…对象包装器主要是定义了更加明确的使用方法。

package df.middleware.mybatis.reflection.wrapper

/** * @description 对象包装器 * 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型, * 它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。添加属性方法 */public interface ObjectWrapper {    // get    Object get(PropertyTokenizer prop);    // set    void set(PropertyTokenizer prop, Object value);    // 查找属性    String findProperty(String name, boolean useCamelCaseMapping);    // 取得getter的名字列表    String[] getGetterNames();    // 取得setter的名字列表    String[] getSetterNames();    //取得setter的类型    Class getSetterType(String name);    // 取得getter的类型    Class getGetterType(String name);    // 是否有指定的setter    boolean hasSetter(String name);    // 是否有指定的getter    boolean hasGetter(String name);    // 实例化属性    MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);    // 是否是集合    boolean isCollection();    // 添加属性    void add(Object element);    // 添加属性     void addAll(List element);}

BaseWrapper:基础对象包装器,抽象类,实现ObjectWapper,主要是抽取公共代码,方便由各子类对象包装器使用,如处理集合则可调用基础对象包装器方法即可,此类主要处理解析集合、获取集合、设置集合中的值

/** * @description 对象包装器抽象基类,提供一些工具方法 * BaseWrapper 抽象类 定义了集合的相关操作。 * 1.解析集合 * 2.获取集合中的值 * 3.设置集合中的值 * */public abstract class BaseWrapper implements ObjectWrapper {    protected static final Object[] NO_ARGUMENTS = new Object[0];    protected MetaObject metaObject;    protected BaseWrapper(MetaObject metaObject) {        this.metaObject = metaObject;    }    /**     * 解析集合     */    protected Object resolveCollection(PropertyTokenizer prop, Object object) {        if ("".equals(prop.getName())) {            return object;        } else {            return metaObject.getValue(prop.getName());        }    }    /**     * 取集合的值     * 中括号有2个意思,一个是Map,一个是List或数组     */    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.");            }        }    }    /**     * 设集合的值     * 中括号有2个意思,一个是Map,一个是List或数组     */    protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {        if (collection instanceof Map) {            ((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.");            }        }    }}

MapWrapper:Map对象包装器,是对Map对象的封装,继承了 BaseWrapper,构造传入map类型对象,获取设置值等等也以map方式即可。

/** * @description Map 包装器 * MapWrapper 是 Map 集合对象的封装。*/public class MapWrapper extends BaseWrapper {    // 原来的对象    private Map map;    public MapWrapper(MetaObject metaObject, Map map) {        super(metaObject);        this.map = map;    }    // get,set是允许的,    @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) {        if (prop.getIndex() != null) {            Object collection = resolveCollection(prop, map);            setCollectionValue(prop, collection, value);        } else {            map.put(prop.getName(), value);        }    }    @Override    public String findProperty(String name, boolean useCamelCaseMapping) {        return name;    }    @Override    public String[] getGetterNames() {        return map.keySet().toArray(new String[map.keySet().size()]);    }    @Override    public String[] getSetterNames() {        return map.keySet().toArray(new String[map.keySet().size()]);    }    @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 map = new HashMap();        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  void addAll(List element) {        throw new UnsupportedOperationException();    }}

CollectionWrapper:Collection对象包装器,实现ObjectWapper接口,除了添加集合、暂不支持其他操作,抛出异常即可。

/** * @author 小傅哥,微信:fustack * @description Collection 包装器 */public class CollectionWrapper implements ObjectWrapper{    // 原来的对象    private Collection object;    public CollectionWrapper(MetaObject metaObject, Collection object) {        this.object = object;    }    // get,set都是不允许的,只能添加元素    @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 useCamelCaseMapping) {        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  void addAll(List element) {        object.addAll(element);    }}

BeanWrapper:原始对象的封装,自定义对象封装,继承BaseWapper,这个是重点,因为是Bean对象,我们需要解析类里属性以及get,set方法,此时我们需要通过元类进入反射器进行解析,所以BeanWrapper依赖MetaClass

/** * @description Bean 包装器 * BeanWrapper 是原始对象的封装 */public class BeanWrapper extends BaseWrapper {    // 原来的对象    private Object object;    // 元类    private MetaClass metaClass;    public BeanWrapper(MetaObject metaObject, Object object) {        super(metaObject);        this.object = object;        // 通过元类获取反射器 1个入口        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);        }    }    @Override    public void set(PropertyTokenizer prop, Object value) {        // 如果有index,说明是集合,那就要解析集合,调用的是BaseWrapper.resolveCollection 和 setCollectionValue        if (prop.getIndex() != null) {            Object collection = resolveCollection(prop, object);            setCollectionValue(prop, collection, value);        } else {            // 否则,setBeanProperty            setBeanProperty(prop, object, value);        }    }    @Override    public String findProperty(String name, boolean useCamelCaseMapping) {        return metaClass.findProperty(name, useCamelCaseMapping);    }    @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 (metaClass.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 (metaClass.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.toString(), e);        }        return metaValue;    }    @Override    public boolean isCollection() {        return false;    }    @Override    public void add(Object element) {        throw new UnsupportedOperationException();    }    @Override    public  void addAll(List list) {        throw new UnsupportedOperationException();    }    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("Could not get property '" + prop.getName() + "' from " + object.getClass() + ".  Cause: " + t.toString(), t);        }    }    private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {        try {            // 得到setter方法,然后调用            Invoker method = metaClass.getSetInvoker(prop.getName());            Object[] params = {value};            method.invoke(object, params);        } catch (Throwable t) {            throw new RuntimeException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);        }    }}

3.5 元对象

有了元类,反射器,对象包装器,最后我们统一一个元对象进行封装,对外统一调用方式,组成一个完整的元对象操作类。通过构造方法创建不同的对象包装器,获取此类中方法则自然调度到不同的wapper包装器里,实现整条链路

/** * @description 元对象 * */public class MetaObject {    // 原对象    private Object originalObject;    /**     * 封装过的 Object 对象     */    // 对象包装器    private ObjectWrapper objectWrapper;    // 对象工厂    private ObjectFactory objectFactory;    // 对象包装工厂    private ObjectWrapperFactory objectWrapperFactory;    // 赋值为不同的包装器    private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {        this.originalObject = object;        this.objectFactory = objectFactory;        this.objectWrapperFactory = objectWrapperFactory;        if (object instanceof ObjectWrapper) {            // 如果对象本身已经是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);        }    }    /**     * 创建 MetaObject 对象     *     * @param object 原始 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 ObjectFactory getObjectFactory() {        return objectFactory;    }    public ObjectWrapperFactory getObjectWrapperFactory() {        return objectWrapperFactory;    }    public Object getOriginalObject() {        return originalObject;    }    /* --------以下方法都是委派给 ObjectWrapper------ */    // 查找属性,相当于又封装了一层    public String findProperty(String propName, boolean useCamelCaseMapping) {        return objectWrapper.findProperty(propName, useCamelCaseMapping);    }    /**     * 获取get方法属性名称和get方法去掉get后边的属性名称     * getIds(){return id;} --> (id、ids)     * @return     */    // 取得getter的名字列表    public String[] getGetterNames() {        return objectWrapper.getGetterNames();    }    /**     * 获取set方法属性名称和set方法去掉set后边的属性名称     * setIds(){return id;} --> (id、ids)     * @return     */    // 取得setter的名字列表    public String[] getSetterNames() {        return objectWrapper.getSetterNames();    }    /**     * 获取set方法后边属性的类型     * @param name 这个name 要和setXXX方法中的XXX相同才能获取到,否则抛异常     * @return     */    // 取得setter的类型列表    public Class getSetterType(String name) {        return objectWrapper.getSetterType(name);    }    /**     * 获取get方法后边属性的类型     * @param name 这个name,要个getXXX方法中的XXX相同才能获取到,否则抛异常     * @return     */    // 取得getter的类型列表    public Class getGetterType(String name) {        return objectWrapper.getGetterType(name);    }    /**     * 判断name是否是setXXX()方法中的XXX     * @param name     * @return     */    //是否有指定的setter    public boolean hasSetter(String name) {        return objectWrapper.hasSetter(name);    }    /**     * 判断name是否是getXXX()方法中的XXX     * @param name     * @return     */    // 是否有指定的getter    public boolean hasGetter(String name) {        return objectWrapper.hasGetter(name);    }    /**     * 获取对象属性值,可以递归获取     * @param name     * @return     */    // 取得值    // 如 班级[0].学生.成绩    public Object getValue(String name) {        // 创建 PropertyTokenizer 对象,对 name 分词        PropertyTokenizer prop = new PropertyTokenizer(name);        // 有子表达式        if (prop.hasNext()) {            // 创建 MetaObject 对象,递归调用            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());            // 递归判断子表达式 children ,获取值,metaValue == null,则返回null            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {                // 如果上层就是null了,那就结束,返回null                return null;            } else {                // 否则继续看下一层,递归调用getValue                return metaValue.getValue(prop.getChildren());            }        } else {            // 无子表达式,取值            return objectWrapper.get(prop);        }    }    /**     * 给对象属性设置值,可以递归设置,基本类型,数组,对象,都可以自动创建     * 但是ArrayList和数组需要手动创建     * List必须创建对象,添加进list     * @param name     * @param value     */    // 如 班级[0].学生.成绩    public void setValue(String name, Object value) {        // 创建 PropertyTokenizer 对象,对 name 分词        PropertyTokenizer prop = new PropertyTokenizer(name);        // 有子表达式        if (prop.hasNext()) {            // 创建 MetaObject 对象            MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());            // 递归判断子表达式 children ,设置值            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {                if (value == null && prop.getChildren() != null) {                    // don't instantiate child path if value is 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);        }    }    // 为属性生成元对象    public MetaObject metaObjectForProperty(String name) {        // 实际是递归调用        Object value = getValue(name);        return MetaObject.forObject(value, objectFactory, objectWrapperFactory);    }    public ObjectWrapper getObjectWrapper() {        return objectWrapper;    }    // 是否是集合    public boolean isCollection() {        return objectWrapper.isCollection();    }    // 添加属性    public void add(Object element) {        objectWrapper.add(element);    }    // 添加属性    public  void addAll(List list) {        objectWrapper.addAll(list);    }}

3.6 系统元对象

SystemMetaObject:可通过此类获取元对象

/** * @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() {        // Prevent Instantiation of Static Class    }    /**     * 空对象     */    private static class NullObject {    }    public static MetaObject forObject(Object object) {        return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);    }}

3.7 对象工厂

ObjectFactory:对象工厂接口,创建对象处理

/** * @description 对象工厂接口*/public interface ObjectFactory {    /**     * Sets configuration properties.     * 设置属性     * @param properties configuration properties     */    void setProperties(Properties properties);    /**     * Creates a new object with default constructor.     * 生产对象     * @param type Object type     * @return      */     T create(Class type);    /**     * Creates a new object with the specified constructor and params.     * 生产对象,使用明确的构造函数和构造函数参数     * @param type Object type     * @param constructorArgTypes Constructor argument types     * @param constructorArgs Constructor argument values     * @return      */     T create(Class type, List<Class> constructorArgTypes, List constructorArgs);    /**     * Returns true if this object can have a set of other objects.     * It's main purpose is to support non-java.util.Collection objects like Scala collections.     * 返回这个对象是否是集合,为了支持 Scala collections     *     * @since 3.1.0     * @param type Object type     * @return whether it is a collection or not     */     boolean isCollection(Class type);}

DefaultObjectFactory:默认对象工厂,实现对象工厂,对象实例化操作,在对象包装器中复杂场景有子集合对象时进行对象生成操作。

/** * @description 默认对象工厂,所有的对象都有工厂来生成*/public class DefaultObjectFactory implements ObjectFactory, Serializable {    private static final long serialVersionUID = -8855120656740914948L;    @Override    public void setProperties(Properties properties) {        // no props for default 默认无属性可设置    }    @Override    public  T create(Class type) {        return create(type, null, null);    }    @SuppressWarnings("unchecked")    @Override    public  T create(Class type, List<Class> constructorArgTypes, List constructorArgs) {        // 1. 解析接口        Class classToCreate = resolveInterface(type);        // 2. 类实例化        return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);    }    private  T instantiateClass(Class type, List<Class> constructorArgTypes, List constructorArgs) {        try {            Constructor 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[constructorArgTypes.size()]));            if (!constructor.isAccessible()) {                constructor.setAccessible(true);            }            return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));        } catch (Exception e) {            // 如果出错,包装一下,重新抛出自己的异常            StringBuilder argTypes = new StringBuilder();            if (constructorArgTypes != null) {                for (Class argType : constructorArgTypes) {                    argTypes.append(argType.getSimpleName());                    argTypes.append(",");                }            }            StringBuilder argValues = new StringBuilder();            if (constructorArgs != null) {                for (Object argValue : constructorArgs) {                    argValues.append(argValue);                    argValues.append(",");                }            }            throw new RuntimeException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);        }    }    @Override    public  boolean isCollection(Class type) {        return Collection.class.isAssignableFrom(type);    }    /**     * 解析接口,将 interface 转换为实际的 class 类     */    protected 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;    }}

3.8 属性命名器

/** * @description 属性命名器 * namer 命名者 */public class PropertyNamer {    private PropertyNamer() {    }    /**     * 方法转换为属性     */    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' or '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的方法     */    public static boolean isProperty(String name) {        return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");    }    /**     * 是否为 getter     */    public static boolean isGetter(String name) {        return name.startsWith("get") || name.startsWith("is");    }    /**     * 是否为 setter     */    public static boolean isSetter(String name) {        return name.startsWith("set");    }}

3.9 属性分解器

PropertyTokenizer:此类贯穿整个工具使用,主要是解析属性是不是只是简单属性还是复杂属性,如果有集合,需要解析下标,子集合名称等操作

/** * @description 属性分解标记 * 可以解析处理简单属性以及list集合Map等等的数据 * 亮点:可迭代,可以看看 */public class PropertyTokenizer implements Iterable, Iterator {    // 例子:班级[0].学生.成绩    // 班级,父表达式    private String name;    // 班级[0],带索引的表达式,由父表达式和下标组成    private String indexedName;    // 0 ,下标,该属性只对字段类型为map|list|array类型的字段有效,对于list和array类型的字段,index保存的是下标。    private String index;    // 学生.成绩,,子表达式:该属性只对嵌套表达式有效    private String children;    public PropertyTokenizer(String fullname) {        // 班级[0].学生.成绩        // 找这个点 .        // 解析出parent表达式和children表达式        int delim = fullname.indexOf('.');        if (delim > -1) {            name = fullname.substring(0, delim);//截取到parent表达式            children = fullname.substring(delim + 1);//截取到children表达式        } else {            // 找不到.的话,取全部部分            name = fullname;//fullname 即为parent表达式            children = null;//无children        }        indexedName = name;        // 把中括号里的数字给解析出来        delim = name.indexOf('[');        if (delim > -1) {//如果有下标            index = name.substring(delim + 1, name.length() - 1);保存下标到index            name = name.substring(0, delim);//3.截取出field name,        }    }    public String getName() {        return name;    }    public String getIndex() {        return index;    }    public String getIndexedName() {        return indexedName;    }    public String getChildren() {        return children;    }    @Override    public boolean hasNext() {        return children != null;    }    // 取得下一个,非常简单,直接再通过儿子来new另外一个实例    @Override    public PropertyTokenizer next() {        return new PropertyTokenizer(children);    }    @Override    public void remove() {        throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");    }    @Override    public Iterator iterator() {        return this;    }}

3.10 使用反射器数据源属性设置

那我们先来把UnpooledDataSourceFactory的数据源属性进行设置

public class UnpooledDataSourceFactory implements DataSourceFactory {    protected DataSource dataSource;    public UnpooledDataSourceFactory() {        this.dataSource = new UnpooledDataSource();    }    protected Properties pros;    @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的类型,将配置文件中的值强转成相应的类型     */    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;    }}

到此我们所有的类都介绍完毕了,我们用单元测试可以测试下,测试准备和上几节一样,可直接运行debug看下通过反射将DataSource的驱动 ,用户名,密码等反射设置进来

完事,本节所有的代码都已完全展现,大家想要源码可以去bugStack冲动栈,小傅哥那里

Copyright © maxssl.com 版权所有 浙ICP备2022011180号