easy-mapper 源码分析

来源:互联网 发布:windows时间服务未运行 编辑:程序博客网 时间:2024/06/05 17:56

问题:
在编写程序的过程中,我们会将bean按照业务的不同分作po,ao,pojo,dto等等。一个业务联下来经常会遇到不同bean之间的转换工作,像下面这样:
Student t = new Student();
t.setName(studentDto.getName());
t.setId(studentDto.getId());
t.setEmail(studentDto.getEmail());
……

这样的代码在bean里的属性异常丰富的时候会变的非常麻烦,我们不得不去写一些工厂类来完成这些功能。这样我们可能会写出N多个assemb方法出来。到这里我们就会感觉很不爽了,于是我们又写了一个利用反射自动设置的通用方法。但是之后又会发现其他的一些特例的问题(比如有的属性我不想要之类的......)修改原来方法的成本比较高,导致我们又回到上面的麻烦的代码中。easy-mapper就是帮我们做这个事情的,这个是百度的一个叫张旭的人物写的,下面贴出github地址

github地址:> https://github.com/neoremind/easy-mapper

使用异常简单maven项目直接引用

<dependency>    <groupId>com.baidu.unbiz</groupId>    <artifactId>easy-mapper</artifactId>    <version>1.0.2</version></dependency>
Person p = new Person();p.setFirstName("NEO");p.setLastName("jason");p.setJobTitles(Lists.newArrayList("abc", "dfegg", "iii"));p.setSalary(1000L);PersonDto dto = MapperFactory.getCopyByRefMapper()                .mapClass(Person.class, PersonDto.class)                .registerAndMap(p, PersonDto.class);System.out.println(dto);

上面是用法,下面我开始分析源码的一些重要逻辑(欢迎指正)

项目包展示

在codegen包下存放的是相关字节码增强功能实现的辅助类,框架实现的类转换功能依赖的是字节码增强生成的代码,这种技术效率很高,而且作者在生成一次之后又将生成的类加入到缓存中,下次再调用就直接从缓存拿了,更加提升了转换效率。在github上作者给出了和同类插件的性能对比图,虽然算不上顶尖,但是好在使用方便,学习成本很低,已经很优秀了
有关字节码增强技术的文章请看这里

http://blog.chinaunix.net/uid-21718047-id-3337821.html

这里写图片描述

上面的create Object number是转换对象的个数

exception包下是默认的异常处理

mapping包下是针对两个类之中的匹配属性不同类型之间的转换策略

metadata包下是转换过程中使用的数据源bean,之中包含了一些本类使用的工具方法

util包下是一些公共的公用类

根目录下的几个类是用来暴露给开发人员的入口类

下面我们跟踪一条主要的业务线来梳理逻辑,从使用的类入手

PersonDto dto = MapperFactory.getCopyByRefMapper()                .mapClass(Person.class, PersonDto.class)                .registerAndMap(p, PersonDto.class);

MapperFactory

MapperFactory.getCopyByRefMapper方法会返回一个单例的Mapper类,Mapper是一个接口,实现类只有 CopyByRefMapper 这一个,下面看看这个类里搞了什么

Mapper

Mapper是一个接口,里面提供了源类转换成目标类map方法的不同参数的实现,以及注册控件(或者初始化),清理缓存的方法

CopyByRefMapper

这个类的构造方法里初始化了三个属性

  /**     * 构造方法     */    public CopyByRefMapper() {        this.classMapCache = new Memoizer<MapperKey, ClassMap<Object, Object>>();        this.mapperCache = new Memoizer<MapperKey, AtoBMapping<Object, Object>>();        codeGenerator = new MappingCodeGenerator();    }

classMapCache 和 mapperCache 都是用来做代码缓存的
codeGenerator是代码生成器 这两个我们先不关注,先关注主干

MapperFactory.getCopyByRefMapper()方法发挥的Mapper类后又调用了生成的这个Mapper(其实就是CopyByRefMapper)类的mapClass方法,看看这个方法里面搞了什么事情

 @Override    public <A, B> ClassMapBuilder<A, B> mapClass(Class<A> aType, Class<B> bType) {        return new ClassMapBuilder<A, B>(TypeFactory.valueOf(aType), TypeFactory.valueOf(bType), this);    }

这个方法里返回了一个ClassMap的构造器ClassMapBuilder,看看这个类里面是什么东西

ClassMapBuilder

这个类的构造方法长这个样子

  /**     * 构造方法     *     * @param aType  源类型     * @param bType  目标类型     * @param mapper 客户端调用的入口mapper     */    public ClassMapBuilder(Type<A> aType, Type<B> bType, Mapper mapper) {        this.aType = aType;        this.bType = bType;        this.mapper = mapper;        propertyResolver = new IntrospectorPropertyResolver();    }

这三个入参我们来看看,他是这样构造的

 return new ClassMapBuilder<A, B>(TypeFactory.valueOf(aType), TypeFactory.valueOf(bType), this);

TypeFactory

TypeFactory.valueOf(aType) 做了什么:

  public static <E> Type<E> valueOf(final Class<E> rawType) {        if (rawType == null) {            return null;        } else if (rawType.isAnonymousClass() && rawType.getGenericSuperclass() instanceof ParameterizedType) {            ParameterizedType genericSuper = (ParameterizedType) rawType.getGenericSuperclass();            return valueOf(genericSuper);        } else {            return intern(rawType, new java.lang.reflect.Type[0], new HashSet<java.lang.reflect.Type>());        }    }

入参是java.lang包下的class类,出参是本项目metadata包下的Type类,这个是将java原生的类转换成自定义类的一个工具方法。这个方法声明为static 不用考虑并发带来的问题。整个项目的思路就是先将java原生class或者Property属性装换为自定义的类型后,然后再进行匹配转换操作

我们来看看他是怎么转换的

前面第一个if我们不管,第二个是判定内部类的不管,先看最简单的一条逻辑最后的else里

 return intern(rawType, new java.lang.reflect.Type[0], new HashSet<java.lang.reflect.Type>());

看看这个方法里干了什么

    private static <T> Type<T> intern(final Class<T> rawType, final java.lang.reflect.Type[] typeArguments,                                      final Set<java.lang.reflect.Type> recursiveBounds) {        //(1)        Type<?>[] convertedArguments = TypeUtil.convertTypeArguments(rawType, typeArguments, recursiveBounds);        TypeKey key = TypeKey.valueOf(rawType, convertedArguments);        WeakReference<Type<?>> mapped = typeCache.get(key);        Type<T> typeResult = null;        if (mapped != null) {            typeResult = (Type<T>) mapped.get();        }        if (typeResult == null) {            synchronized(rawType) {                mapped = typeCache.get(key);                if (mapped != null) {                    typeResult = (Type<T>) mapped.get();                }                if (typeResult == null) {                    typeResult = createType(key, rawType, convertedArguments);                    mapped = new WeakReference<Type<?>>(typeResult);                    WeakReference<Type<?>> existing = typeCache.putIfAbsent(key, mapped);                    if (existing != null) {                        if (existing.get() == null) {                            typeCache.put(key, mapped);                        } else {                            mapped = existing;                            typeResult = (Type<T>) mapped.get();                        }                    }                }            }        }        return typeResult;    }
  1. 第一步就调用了一个转换方法,将入参为java原生class中的属性转换成了自定义的Type数组类型,跟进去,看到一个static方法,我把理解写到代码里

/***rawType 是原生classactualTypeArguments 是java原生class类的接口类,这个弄了个数组还只有一个长度actualTypeArguments 是一个Type类型的Set**/static Type<?>[] convertTypeArguments(final Class<?> rawType, final java.lang.reflect.Type[] actualTypeArguments,                                          final Set<java.lang.reflect.Type> recursiveBounds) {        //首先获取原生class类的所有属性信息,是一个原生的TypeVariable数组        TypeVariable<?>[] typeVariables = rawType.getTypeParameters();        //申明一个自定义Type类型数组备用        Type<?>[] resultTypeArguments = new Type<?>[typeVariables.length];            //判断set里边包含当前这个Type吗?第一次来肯定是不包含的,跳过        if (recursiveBounds.contains(rawType)) {            return new Type<?>[0];        }        //actualTypeArguments.length == 0 && typeVariables.length > 0 这个判断成立,进去 else if (actualTypeArguments.length == 0 && typeVariables.length > 0) { //将当前的class对象加到set中            recursiveBounds.add(rawType);            //下面这个将原生类转换成自定义的Type类型,看解释(2)            resultTypeArguments = convertTypeArgumentsFromAncestry(rawType, recursiveBounds);            recursiveBounds.remove(rawType);        } else if (actualTypeArguments.length < typeVariables.length) {            throw new IllegalArgumentException("Must provide all type-arguments or none");        } else {            for (int i = 0, len = actualTypeArguments.length; i < len; ++i) {                java.lang.reflect.Type t = actualTypeArguments[i];                recursiveBounds.add(rawType);                resultTypeArguments[i] = TypeFactory.limitedValueOf(t, recursiveBounds);                recursiveBounds.remove(rawType);            }        }        return resultTypeArguments;    }

(2)

resultTypeArguments = convertTypeArgumentsFromAncestry(rawType, recursiveBounds);
/** 这个第一个参数是原生class对象 第二个参数是将上面的class对象用Set包装了下*/ static Type<?>[] convertTypeArgumentsFromAncestry(final Class<?> rawType,                                                      final Set<java.lang.reflect.Type> bounds) {//声明了一个LinkedHashMap备用        Map<TypeVariable<?>, Type<?>> typesByVariable = new LinkedHashMap<TypeVariable<?>, Type<?>>();        //从原生的class对象中获取属性列表,并将属性列表添加到上面的LinkedHashMap        for (TypeVariable<?> var : rawType.getTypeParameters()) {            typesByVariable.put(var, TypeFactory.limitedValueOf(var, bounds));        }        //新建一个原生Type类型的set        Set<java.lang.reflect.Type> genericAncestors = new LinkedHashSet<java.lang.reflect.Type>();        genericAncestors.add(rawType.getGenericSuperclass());        genericAncestors.add(rawType.getSuperclass());        genericAncestors.addAll(Arrays.asList(rawType.getGenericInterfaces()));        genericAncestors.addAll(Arrays.asList(rawType.getInterfaces()));        Iterator<java.lang.reflect.Type> iter = genericAncestors.iterator();        while (iter.hasNext()) {            java.lang.reflect.Type ancestor = iter.next();            iter.remove();            if (ancestor instanceof ParameterizedType) {                ParameterizedType superType = (ParameterizedType) ancestor;                TypeVariable<?>[] variables = ((Class<?>) superType.getRawType()).getTypeParameters();                java.lang.reflect.Type[] actuals = superType.getActualTypeArguments();                for (int i = 0; i < variables.length; ++i) {                    Type<?> resolvedActual = TypeFactory.limitedValueOf(actuals[i], bounds);                    TypeVariable<?> var =                            (TypeVariable<?>) ((actuals[i] instanceof TypeVariable) ? actuals[i] : variables[i]);                    Type<?> currentActual = typesByVariable.get(var);                    if (currentActual != null) {                        typesByVariable.put(var, getMostSpecificType(currentActual, resolvedActual));                    }                }            } else if (ancestor instanceof Class) {                Class<?> superType = (Class<?>) ancestor;                TypeVariable<?>[] variables = superType.getTypeParameters();                for (int i = 0; i < variables.length; ++i) {                    Type<?> resolvedActual = TypeFactory.limitedValueOf(variables[i], bounds);                    Type<?> currentActual = typesByVariable.get(variables[i]);                    if (currentActual != null) {                        typesByVariable.put(variables[i], getMostSpecificType(currentActual, resolvedActual));                    }                }            }        }        return typesByVariable.values().toArray(new Type<?>[0]);    }

未完待续。。。。

0 0
原创粉丝点击