Redkale 技术详解 04 -- Java DataSource简易的DB操作
+ ++ 长期以来,Hibernate和Mybatis一直是大家使用最多的持久层开发框架。针对这两种框架网络上是各种比较,各种讨论优缺点。其实这两个框架都是2002年左右发布的(算上前身ibatis),如同当年Spring鄙视JavaEE是庞然大物一样,现如今Spring、Hibernate、Mybatis这些老框架经历了15个年头也已笨重不堪,Mybatis的jar包近6M,Hibernate加上依赖包更是大得离谱。一个Tomcat(不算webapps)也不过才7-8M, 而一个DB框架 +
++ 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 +
+ + + +