`
Donald_Draper
  • 浏览: 984429 次
社区版块
存档分类
最新评论

Mybatis的Reflector解析

阅读更多
Mybatis的MetaObject解析:http://donald-draper.iteye.com/admin/blogs/2338818
在上篇分析MetaObejct时候,MetaObejct的方法的实现是依赖ObjectWrapper,ObjectWrapper依赖于MetaClass,而MetaClass依赖于Reflector,这一节我们就来看看Reflector
//Reflector
public class Reflector
{
    private static boolean classCacheEnabled = true;
    private static final String EMPTY_STRING_ARRAY[] = new String[0];
    private static final Map REFLECTOR_MAP = new ConcurrentHashMap();
    private Class type;
    private String readablePropertyNames[];//可读属性名
    private String writeablePropertyNames[];//可写属性名
    private Map setMethods;Map<String,MethodInvoker>
    private Map getMethods;Map<String,MethodInvoker>
    private Map setTypes;Map<String,Class>
    private Map getTypes;Map<String,Class>
    private Constructor defaultConstructor;//默认构造函数
    private Map caseInsensitivePropertyMap;//大小写不敏感属性Map
    //构造Class对应的Reflector
    public static Reflector forClass(Class clazz)
    {
        if(classCacheEnabled)
        {
	    //如果缓存状态开启,则从REFLECTOR_MAP获取对应的Reflector,没有则重新构建
            Reflector cached = (Reflector)REFLECTOR_MAP.get(clazz);
            if(cached == null)
            {
                cached = new Reflector(clazz);
                REFLECTOR_MAP.put(clazz, cached);
            }
            return cached;
        } else
        {
            return new Reflector(clazz);
        }
    }
    private Reflector(Class clazz)
    {
        readablePropertyNames = EMPTY_STRING_ARRAY;//可读属性名
        writeablePropertyNames = EMPTY_STRING_ARRAY;//可写属性名
        setMethods = new HashMap();//Set方法Map
        getMethods = new HashMap();//Get方法Map
        setTypes = new HashMap();
        getTypes = new HashMap();
        caseInsensitivePropertyMap = new HashMap();//大小写不敏感属性Map
        type = clazz;
        addDefaultConstructor(clazz);
        addGetMethods(clazz);
        addSetMethods(clazz);
        addFields(clazz);
        readablePropertyNames = (String[])getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
        writeablePropertyNames = (String[])setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
        //将可读属性添加大小写不敏感属性Map
	String arr$[] = readablePropertyNames;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            String propName = arr$[i$];
            caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }
        //将可写属性添加大小写不敏感属性Map
        arr$ = writeablePropertyNames;
        len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            String propName = arr$[i$];
            caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
        }

    }
}

来看addDefaultConstructor
初始化默认构造函数为,无参构造函数
private void addDefaultConstructor(Class clazz)
    {
        Constructor consts[] = clazz.getDeclaredConstructors();
        Constructor arr$[] = consts;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Constructor constructor = arr$[i$];
            if(constructor.getParameterTypes().length != 0)
                continue;
            if(canAccessPrivateMethods())
                try
                {
                    constructor.setAccessible(true);
                }
                catch(Exception e) { }
            if(constructor.isAccessible())
                defaultConstructor = constructor;
        }

    }

来看addGetMethods
将Class的Get方法添加到
 private void addGetMethods(Class cls)
    {
        Map conflictingGetters = new HashMap();
        Method methods[] = getClassMethods(cls);
        Method arr$[] = methods;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Method method = arr$[i$];
            String name = method.getName();
            if(name.startsWith("get") && name.length() > 3)
            {
                if(method.getParameterTypes().length == 0)
                {
                    name = PropertyNamer.methodToProperty(name);
		    //将name对应的get方法添加到conflictingGetters-Map中
                    addMethodConflict(conflictingGetters, name, method);
                }
                continue;
            }
            if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0)
            {
                name = PropertyNamer.methodToProperty(name);
                addMethodConflict(conflictingGetters, name, method);
            }
        }
        //解决方法冲突
        resolveGetterConflicts(conflictingGetters);
    }
     private void addMethodConflict(Map conflictingMethods, String name, Method method)
    {
        List list = (List)conflictingMethods.get(name);
        if(list == null)
        {
            list = new ArrayList();
            conflictingMethods.put(name, list);
        }
        list.add(method);
    }

     private void resolveGetterConflicts(Map conflictingGetters)
    {
        for(Iterator i$ = conflictingGetters.keySet().iterator(); i$.hasNext();)
        {
            String propName = (String)i$.next();
            List getters = (List)conflictingGetters.get(propName);
            Iterator iterator = getters.iterator();
            Method firstMethod = (Method)iterator.next();
            if(getters.size() == 1)
            {
                addGetMethod(propName, firstMethod);
            } else
            {
                Method getter = firstMethod;
                Class getterType = firstMethod.getReturnType();
                do
                {
                    if(!iterator.hasNext())
                        break;
                    Method method = (Method)iterator.next();
                    Class methodType = method.getReturnType();
                    if(methodType.equals(getterType))
                        throw new ReflectionException((new StringBuilder()).append("Illegal overloaded getter method with ambiguous type for property ").append(propName).append(" in class ").append(firstMethod.getDeclaringClass()).append(".  This breaks the JavaBeans ").append("specification and can cause unpredicatble results.").toString());
                    if(!methodType.isAssignableFrom(getterType))
                        if(getterType.isAssignableFrom(methodType))
                        {
                            getter = method;
                            getterType = methodType;
                        } else
                        {
                            throw new ReflectionException((new StringBuilder()).append("Illegal overloaded getter method with ambiguous type for property ").append(propName).append(" in class ").append(firstMethod.getDeclaringClass()).append(".  This breaks the JavaBeans ").append("specification and can cause unpredicatble results.").toString());
                        }
                } while(true);
		//将name对应的get方法添加到getMethods集合中
                addGetMethod(propName, getter);
            }
        }

    }
    //将name对应的get方法添加到getMethods集合中
    private void addGetMethod(String name, Method method)
    {
        if(isValidPropertyName(name))
        {
            getMethods.put(name, new MethodInvoker(method));
            getTypes.put(name, method.getReturnType());
        }
    }

来看addSetMethods
private void addSetMethods(Class cls)
    {
        Map conflictingSetters = new HashMap();
        Method methods[] = getClassMethods(cls);
        Method arr$[] = methods;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Method method = arr$[i$];
            String name = method.getName();
            if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1)
            {
                name = PropertyNamer.methodToProperty(name);
		//将name对应的set方法添加到conflictingSetters-Map中
                addMethodConflict(conflictingSetters, name, method);
            }
        }
        //解决方法冲突
        resolveSetterConflicts(conflictingSetters);
    }

    private void addMethodConflict(Map conflictingMethods, String name, Method method)
    {
        List list = (List)conflictingMethods.get(name);
        if(list == null)
        {
            list = new ArrayList();
            conflictingMethods.put(name, list);
        }
        list.add(method);
    }

    private void resolveSetterConflicts(Map conflictingSetters)
    {
        Iterator i$ = conflictingSetters.keySet().iterator();
        do
        {
            if(!i$.hasNext())
                break;
            String propName = (String)i$.next();
            List setters = (List)conflictingSetters.get(propName);
            Method firstMethod = (Method)setters.get(0);
            if(setters.size() == 1)
            {
                addSetMethod(propName, firstMethod);
                continue;
            }
            Class expectedType = (Class)getTypes.get(propName);
            if(expectedType == null)
                throw new ReflectionException((new StringBuilder()).append("Illegal overloaded setter method with ambiguous type for property ").append(propName).append(" in class ").append(firstMethod.getDeclaringClass()).append(".  This breaks the JavaBeans ").append("specification and can cause unpredicatble results.").toString());
            Iterator methods = setters.iterator();
            Method setter = null;
            do
            {
                if(!methods.hasNext())
                    break;
                Method method = (Method)methods.next();
                if(method.getParameterTypes().length != 1 || !expectedType.equals(method.getParameterTypes()[0]))
                    continue;
                setter = method;
                break;
            } while(true);
            if(setter == null)
                throw new ReflectionException((new StringBuilder()).append("Illegal overloaded setter method with ambiguous type for property ").append(propName).append(" in class ").append(firstMethod.getDeclaringClass()).append(".  This breaks the JavaBeans ").append("specification and can cause unpredicatble results.").toString());
            //将对应的set方法添加到setMethods-map中
	    addSetMethod(propName, setter);
        } while(true);
    }

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

来看addFields
private void addFields(Class clazz)
    {
        Field fields[] = clazz.getDeclaredFields();
        Field arr$[] = fields;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Field field = arr$[i$];
            if(canAccessPrivateMethods())
                try
                {
                    field.setAccessible(true);
                }
                catch(Exception e) { }
            if(!field.isAccessible())
                continue;
            if(!setMethods.containsKey(field.getName()))
                addSetField(field);
            if(!getMethods.containsKey(field.getName()))
                addGetField(field);
        }

        if(clazz.getSuperclass() != null)
            addFields(clazz.getSuperclass());
    }
    //将Field的对应set方法,及参数类型添加到setMethods,setTypes-Map中
    private void addSetField(Field field)
    {
        if(isValidPropertyName(field.getName()))
        {
            setMethods.put(field.getName(), new SetFieldInvoker(field));
            setTypes.put(field.getName(), field.getType());
        }
    }
    //将Field的对应get方法,及参数类型添加到setMethods,setTypes-Map中
    private void addGetField(Field field)
    {
        if(isValidPropertyName(field.getName()))
        {
            getMethods.put(field.getName(), new GetFieldInvoker(field));
            getTypes.put(field.getName(), field.getType());
        }
    }

总结:
从以上分析,Reflector构造函数,所做的工作为,初始构造函数,将Class的set与get方法及参数添加到setMethods,getMethods,setTypes,getTypes对应的Map中,setMethods,getMethods Map的key属性名,value为对应的方法,然后初始化可读,可写,及大小写不明感属性集合。
0
0
分享到:
评论

相关推荐

    MyBatis日志解析工具

    MyBatis日志解析工具支持MyBatis3.0以上版本,能够将Mybatis打印的SQL日志转换成SQL语句。 使用方法请查看 https://blog.csdn.net/warehouse666/article/details/90111704

    mybatis SQL日志解析

    mybatis SQL日志解析;查看日志时mybatis打印的日志查询条件以及参数不是拼接好的,想复制对应sql在本地执行时比较麻烦,通过前端编写页面进行日志解析,拼接sql中的问号以及参数变课轻松实现

    MyBatis 源码解析:通过源码深入理解 SQL 的执行过程 - GitChat

    MyBatis 源码解析:通过源码深入理解 SQL 的执行过程 抓下来打包成了HTML文件, 方便离线观看

    mybatis解析动态xml sql

    项目需要springboot 可以绕过mybatis xml加载直接解析带标签的sql 演示代码,给需要的码农

    Spring整合Mybatis源码解析

    Spring整合Mybatis源码解析

    Mybatis日志SQL解析工具

    该工具可以将mybatis输出的sql日志提取出来,并将其格式化为可以直接执行的sql语句,节约开发人员时间

    MyBatis源码解析

    MyBatis源码解析

    基于Java的Mybatis源码解析设计源码

    Mybatis源码解析设计源码:该项目基于Java开发,包含37个文件,主要使用Java语言。该项目旨在对Mybatis框架的源代码进行深入解析,以帮助开发者更好地理解和使用Mybatis,提高开发效率和质量。

    Mybatis日志中的SQL解析工具(网页版).html

    Mybatis日志中的SQL解析工具(网页版) 说明:复制日志时,必须注意,日志必须包含Preparing:和Parameters:全部内容,而且日志换行格式要保留,不要复制成纯文本,直接ctrl+c即可。

    Mybatis源码解析

    mybatis源码解析视频的讲解是由某知名老师讲解。包你学完可以完全理解mybatis框架实现原理等。

    mybatis3.x源码深度解析与最佳实践.pdf

    MyBatis 3.x 源码深度解析与最佳实践 MyBatis 是当前最流行的 Java 持久层框架之一,其通过 XML 配置的方式消除了绝大部分 JDBC 重复代码以及参数的设置,结果集的映射。为了更好地学习和理解 MyBatis 背后的设计...

    MyBatis源码分析.pdf

    MyBatis的配置文件解析过程是MyBatis的核心组件之一,负责解析MyBatis的配置文件,并将其转换为 Configuration 对象。配置文件解析过程主要包括解析节点、节点、节点、节点、节点、节点等。 2.1.1 解析节点 节点...

    mybatis sql解析,自动填充sql参数,服务器日志sql直接执行

    mybatis sql解析,自动填充sql参数,服务器日志sql直接执行

    基于Java的HBNU后端学习之SpringBoot、Hibernate及MyBatis源码解析

    该学习项目记录了湖北师范大学后端开发过程中的SpringBoot、Hibernate和MyBatis框架源码解析,包含252个文件,主要包括91个Java源文件、87个XML配置文件、19个YAML文件,以及少量其他类型文件。项目内容旨在帮助...

    MyBatis深度解析与实战应用.zip

    MyBatis作为一款优秀的持久层框架,以其...通过本文的解析与实战应用,相信大家对MyBatis有了更深入的了解和认识。在实际应用中,我们应结合业务需求和技术特点,合理选择和使用MyBatis,以提升系统的性能和稳定性。

    从mybatis日志中解析出可执行的sql语句

    适用场景:生产环境从sql日志获取可执行sql语句 使用方法:从日志中获取完整的sql片段(可以前后多复制一部分,确保准确性),打开html文件,粘贴到输入框中点击解析sql,获得可执行的sql

    mybatise解析配置文件的工具类

    ### MyBatis解析配置文件的工具类知识点解析 在Java Web开发中,MyBatis作为一款优秀的持久层框架,能够极大地简化数据访问层(DAO)的编码工作,提高开发效率。本文将详细介绍一个用于初始化MyBatis环境并提供获取...

    mybatis 3.x源码深度解析与最佳实践.html

    mybatis 3.x源码深度解析与最佳实践.html

    mybatis源码分析思维导图.rar

    在执行SQL后,MyBatis的ParameterHandler、ResultSetHandler和StatementHandler三个接口分别处理参数设置、结果集解析和SQL语句的创建。它们协同工作,确保了数据的正确读写。 思维导图中可能还会涉及MyBatis的插件...

    基于IOC容器实现管理mybatis过程解析

    "基于IOC容器实现管理mybatis过程解析" IOC容器是Inversion of Control的缩写,指的是控制反转容器。在软件设计中,控制反转是一种设计原则,它将对象的控制权从对象本身转移到外部容器中,从而实现了对象之间的松...

Global site tag (gtag.js) - Google Analytics