Redkale

##

Redkale 入门 Convert 组件 Service 组件 Source 组件 Net 组件 Watch 组件 Redkale 插件 技术文章

### 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.Attribute、org.redkale.util.Reproduce。

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