Redkale 技术详解 02

Stella981
• 阅读 494

Redkale 技术详解 02 -- Creator构建对象

org.redkale.util.Creator是采用ASM技术来实现代替反射构造函数的对象构建类。在根据流反序列化成对象、数据表记录转换成对象时都需要构建对象。常见的处理办法是利用反射,如Gson框架中反序列化是通过反射进行对象创建。众所周知反射的性能是比较低的,所以Redkale需要自实现一个对象构建类。

Creator是一个接口, 只有一个public T create(Object... params)方法,可变参数既适合空参数的Constructor也适合含参数的Constructor。得利于Java 8的新语法特性可以在接口上加上静态方法,Creator对象可以通过Creator.create(Class clazz)方法创建。构建原理是通过Constructor的参数来动态创建的。

Constructor<T> constructor0 = null;for (Constructor c : clazz.getConstructors()) {  //优先找public 的构造函数   if (c.getParameterCount() == 0) {        constructor0 = c;        break;    }}if (constructor0 == null) {//其次找非private带ConstructorProperties的构造函数    for (Constructor c : clazz.getDeclaredConstructors()) {        if (Modifier.isPrivate(c.getModifiers())) continue;        if (c.getAnnotation(ConstructorProperties.class) != null) {            constructor0 = c;            break;        }    }}if (constructor0 == null) {//再次找非private且带-parameters编译项的构造函数 java 8以上才支持    for (Constructor c : clazz.getDeclaredConstructors()) {        if (Modifier.isPrivate(c.getModifiers())) continue;        Parameter[] params = c.getParameters();        if (params.length == 0) continue;        boolean flag = true;        for (Parameter param : params) {            try {                clazz.getDeclaredField(param.getName());            } catch (Exception e) {                flag = false;                break;            }        }        if (flag) {            constructor0 = c;            break;        }    }}if (constructor0 == null) {//最后找非private的空构造函数    for (Constructor c : clazz.getDeclaredConstructors()) {        if (Modifier.isPrivate(c.getModifiers())) continue;        if (c.getParameterCount() == 0) {            constructor0 = c;            break;        }    }}

从以上代码可以看出,根据优先级选择Constructor,为了减少学习成本,Creator直接重用了java.beans.ConstructorProperties注解,又因ConstructorProperties只能标记在Constructor上,因此定义一个Creator.ConstructorParameters注解,用于标记在Creator的create方法上。

public class Record {    private final int id;    private String name;    @ConstructorProperties({"id", "name"})    Record(int id, String name) {        this.id = id;        this.name = name;    }    public int getId() {        return id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}Record.class通过ASM自动构建与Record同package的Creator类如下:public final class Record_DynCreator implements Creator<Record> {    @Override    @Creator.ConstructorParameters({"id", "name"})    public Record create(Object... params) {        if (params[0] == null) params[0] = 0;        return new Record((Integer) params[0], (String) params[1]);    }}

如上代码,若构造参数是primitive类,而Creator.create传入的参数可能是null,因此需要给null的primitive对象赋予默认值0。细心的人可能发现了Record的构造函数并不是public的,虽然Record_DynCreator与Record在同一package,但由于两者不是同一个ClassLoader,故不能直接new Record。Redkale曲线救国,通过URLClassLoader的私有方法在Record.class的ClassLoader加载Record_DynCreator。

if (loader instanceof URLClassLoader && !Modifier.isPublic(constructor.getModifiers())) {    try {        final URLClassLoader urlLoader = (URLClassLoader) loader;        final URL url = new URL("memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() {            @Override            protected URLConnection openConnection(URL u) throws IOException {                return new URLConnection(u) {                    @Override                    public void connect() throws IOException {                    }                    @Override                    public InputStream getInputStream() throws IOException {                        return new ByteArrayInputStream(bytes);                    }                };            }        });        Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);        addURLMethod.setAccessible(true);        addURLMethod.invoke(urlLoader, url);        resultClazz = urlLoader.loadClass(newDynName.replace('/', '.'));    } catch (Throwable t) { //异常无需理会, 使用下一种loader方式        t.printStackTrace();    }}

如上代码,构建一个虚拟协议的URL来实现加载,若Record.class的ClassLoader不是URLClassLoader导致resultClazz为null则会抛出异常。

Creator是一个典型通过ASM构建一个简单功能地动态类,同类型还有 org.redkale.util.Attributeorg.redkale.util.Reproduce

转载请注明出处:http://redkale.org/article_creator.html

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
2年前
java反射大全
作者对反射的理解:方法的调用(正常的调用:对象.方法()。反射调用方法:方法.对象())静态属性的调用(正常的调用:类.属性。反射调用:属性.类)常见反射的用法:        1.通过反射获取类Class<?demo1Class
Easter79 Easter79
2年前
Spring的两种代理JDK和CGLIB的区别浅谈
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Stella981 Stella981
2年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Easter79 Easter79
2年前
Spring的两种动态代理:Jdk和Cglib 的区别和实现
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Wesley13 Wesley13
2年前
Java反射技术概述
1.什么是Java反射?  就是正在运行,动态获取这个类的所有信息2.反射机制的作用  a.反编译:.class.java  b.通过反射机制,访问Java对象的属性,方法,构造方法等3.反射机制的应用场景  Jdbc加载驱动  SpringIOC实现  Java框架4.创建对象的两种方式  a.直
Wesley13 Wesley13
2年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Wesley13 Wesley13
2年前
Java重点基础:反射机制
一、什么是反射?Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。二、反射的三种方式
Wesley13 Wesley13
2年前
JDK动态代理
一,什么是代理?代理:本来是自己应该做的事,却请了别人来做,被请的人就是代理对象举例:春节回家买票找人代买,黄牛就是代理对象二,什么是动态代理?代理的对象是变动的,在程序运行过程中产生的.而在程序运行过程中产生对象,这个对象是不固定的,那么可以通过反射来实现,所以动态代理是基于反射实现的.
Wesley13 Wesley13
2年前
Java反射机制详解
一、内容提要:  1、反射机制是什么  2、反射机制能做什么  3、反射机制相关的API  4、通过一个对象获得完整的包名和类名  5、实例化Class类对象  6、获取一个对象的父类与实现的接口  7、获取某个类的全部构造函数  8、通过反射机制实例化一个类的对象  9、获取某个类的全部属性  10、
Wesley13 Wesley13
2年前
Java高级特性—反射和动态代理
1).反射  通过反射的方式可以获取class对象中的属性、方法、构造函数等,一下是实例:2).动态代理  使用场景:      在之前的代码调用阶段,我们用action调用service的方法实现业务即可。    由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改servic