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;
        SimpleEntry<String, Class>[] constructorParameters0 = null; //构造函数的参数

        if (constructor0 == null) {  // 1、查找public的空参数构造函数
            for (Constructor c : clazz.getConstructors()) {
                if (c.getParameterCount() == 0) {
                    constructor0 = c;
                    constructorParameters0 = new SimpleEntry[0];
                    break;
                }
            }
        }
        if (constructor0 == null) {  // 2、查找public带ConstructorProperties注解的构造函数
            for (Constructor c : clazz.getConstructors()) {
                ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
                if (cp == null) continue;
                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, cp.value());
                if (fields != null) {
                    constructor0 = c;
                    constructorParameters0 = fields;
                    break;
                }
            }
        }
        if (constructor0 == null) {  // 3、查找public且不带ConstructorProperties注解的构造函数
            List<Constructor> cs = new ArrayList<>();
            for (Constructor c : clazz.getConstructors()) {
                if (c.getAnnotation(ConstructorProperties.class) != null) continue;
                if (c.getParameterCount() < 1) continue;
                cs.add(c);
            }
            //优先参数最多的构造函数
            cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
            for (Constructor c : cs) {
                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, Type.getConstructorDescriptor(c));
                if (fields != null) {
                    constructor0 = c;
                    constructorParameters0 = fields;
                    break;
                }
            }
        }
        if (constructor0 == null) {  // 4、查找非private带ConstructorProperties的构造函数
            for (Constructor c : clazz.getDeclaredConstructors()) {
                if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
                ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
                if (cp == null) continue;
                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, cp.value());
                if (fields != null) {
                    constructor0 = c;
                    constructorParameters0 = fields;
                    break;
                }
            }
        }
        if (constructor0 == null) {  // 5、查找非private且不带ConstructorProperties的构造函数
            List<Constructor> cs = new ArrayList<>();
            for (Constructor c : clazz.getDeclaredConstructors()) {
                if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
                if (c.getAnnotation(ConstructorProperties.class) != null) continue;
                if (c.getParameterCount() < 1) continue;
                cs.add(c);
            }
            //优先参数最多的构造函数
            cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
            for (Constructor c : cs) {
                SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, Type.getConstructorDescriptor(c));
                if (fields != null) {
                    constructor0 = c;
                    constructorParameters0 = fields;
                    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.Copier


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