|
@@ -0,0 +1,162 @@
|
|
|
|
|
+package com.jfinal.template.expr.ast;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
+import com.jfinal.kit.StrKit;
|
|
|
|
|
+import com.jfinal.proxy.ProxyClassLoader;
|
|
|
|
|
+import com.jfinal.proxy.ProxyCompiler;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 使用 jfinal proxy 机制消除 java.lang.reflect.Method.invoke(...)
|
|
|
|
|
+ * 提升性能,并且同时支持动态类型的 field 表达式取值
|
|
|
|
|
+ */
|
|
|
|
|
+public class FastFieldGetter extends FieldGetter {
|
|
|
|
|
+
|
|
|
|
|
+ protected static ProxyGenerator generator = new ProxyGenerator();
|
|
|
|
|
+ protected static ProxyCompiler compiler = new ProxyCompiler();
|
|
|
|
|
+ protected static ProxyClassLoader classLoader = new ProxyClassLoader();
|
|
|
|
|
+ protected static Map<Class<?>, Proxy> cache = new ConcurrentHashMap<>(512, 0.25F);
|
|
|
|
|
+
|
|
|
|
|
+ protected Proxy proxy;
|
|
|
|
|
+ protected java.lang.reflect.Method getterMethod;
|
|
|
|
|
+
|
|
|
|
|
+ public FastFieldGetter(Proxy proxy, java.lang.reflect.Method getterMethod) {
|
|
|
|
|
+ this.proxy = proxy;
|
|
|
|
|
+ this.getterMethod = getterMethod;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 仅用于配置 Engine.addFieldGetter(0, new FastFieldGetter());
|
|
|
|
|
+ */
|
|
|
|
|
+ public FastFieldGetter() {
|
|
|
|
|
+ this(null, null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public FieldGetter takeOver(Class<?> targetClass, String fieldName) {
|
|
|
|
|
+ if (MethodKit.isForbiddenClass(targetClass)) {
|
|
|
|
|
+ throw new RuntimeException("Forbidden class: " + targetClass.getName());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String getterName = "get" + StrKit.firstCharToUpperCase(fieldName);
|
|
|
|
|
+ java.lang.reflect.Method[] methodArray = targetClass.getMethods();
|
|
|
|
|
+ for (java.lang.reflect.Method method : methodArray) {
|
|
|
|
|
+ if (method.getName().equals(getterName) && method.getParameterCount() == 0) {
|
|
|
|
|
+
|
|
|
|
|
+ Proxy proxy = cache.get(targetClass);
|
|
|
|
|
+ if (proxy == null) {
|
|
|
|
|
+ synchronized (targetClass) {
|
|
|
|
|
+ proxy = cache.get(targetClass);
|
|
|
|
|
+ if (proxy == null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ proxy = createProxy(targetClass, fieldName);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ cache.putIfAbsent(targetClass, proxy);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return new FastFieldGetter(proxy, method);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Object get(Object target, String fieldName) throws Exception {
|
|
|
|
|
+ // return getterMethod.invoke(target, ExprList.NULL_OBJECT_ARRAY);
|
|
|
|
|
+ return proxy.getValue(target, fieldName);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected Proxy createProxy(Class<?> targetClass, String fieldName) {
|
|
|
|
|
+ ProxyClass proxyClass = new ProxyClass(targetClass);
|
|
|
|
|
+ String sourceCode = generator.generate(proxyClass);
|
|
|
|
|
+ // System.out.println(sourceCode);
|
|
|
|
|
+
|
|
|
|
|
+ proxyClass.setSourceCode(sourceCode);
|
|
|
|
|
+ compiler.compile(proxyClass);
|
|
|
|
|
+ Class<?> retClass = classLoader.loadProxyClass(proxyClass);
|
|
|
|
|
+ proxyClass.setClazz(retClass);
|
|
|
|
|
+ try {
|
|
|
|
|
+ return (Proxy)retClass.newInstance();
|
|
|
|
|
+ } catch (ReflectiveOperationException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String toString() {
|
|
|
|
|
+ return getterMethod.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ---------
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 代理接口
|
|
|
|
|
+ */
|
|
|
|
|
+ public static interface Proxy {
|
|
|
|
|
+ public Object getValue(Object target, String fieldName);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ---------
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 代理类
|
|
|
|
|
+ */
|
|
|
|
|
+ static class ProxyClass extends com.jfinal.proxy.ProxyClass {
|
|
|
|
|
+
|
|
|
|
|
+ private String name; // 类名
|
|
|
|
|
+
|
|
|
|
|
+ public ProxyClass(Class<?> target) {
|
|
|
|
|
+ super(target);
|
|
|
|
|
+
|
|
|
|
|
+ name = target.getSimpleName() + "$$EnhancerByJFinal_FieldGetter";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String getName() {
|
|
|
|
|
+ return name;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ---------
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 代理生成器
|
|
|
|
|
+ */
|
|
|
|
|
+ static class ProxyGenerator {
|
|
|
|
|
+
|
|
|
|
|
+ String generate(ProxyClass proxyClass) {
|
|
|
|
|
+ StringBuilder ret = new StringBuilder(1024);
|
|
|
|
|
+
|
|
|
|
|
+ Class<?> targetClass = proxyClass.getTarget();
|
|
|
|
|
+ String className = proxyClass.getName();
|
|
|
|
|
+
|
|
|
|
|
+ ret.append("package ").append(proxyClass.getPkg()).append(";\n\n");
|
|
|
|
|
+ ret.append("import com.jfinal.template.expr.ast.FastFieldGetter.Proxy;\n\n");
|
|
|
|
|
+ ret.append("public class ").append(className).append(" implements Proxy {\n\n");
|
|
|
|
|
+ ret.append("\tpublic Object getValue(Object target, String fieldName) {\n");
|
|
|
|
|
+ ret.append("\t\tint hash = fieldName.hashCode();\n");
|
|
|
|
|
+ ret.append("\t\tswitch (hash) {\n");
|
|
|
|
|
+
|
|
|
|
|
+ java.lang.reflect.Method[] methodArray = targetClass.getMethods();
|
|
|
|
|
+ for (java.lang.reflect.Method method : methodArray) {
|
|
|
|
|
+ String mn = method.getName();
|
|
|
|
|
+ if (method.getParameterCount() == 0 && mn.startsWith("get") && (!mn.equals("getClass"))) {
|
|
|
|
|
+ String fieldName = StrKit.firstCharToLowerCase(mn.substring(3));
|
|
|
|
|
+ ret.append("\t\tcase ").append(fieldName.hashCode()).append(" :\n");
|
|
|
|
|
+ ret.append("\t\t\treturn ((").append(targetClass.getName()).append(")target).").append(mn).append("();\n");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ret.append("\t\tdefault :\n");
|
|
|
|
|
+ ret.append("\t\t\tthrow new RuntimeException(\"Can not access the field \\\"\" + target.getClass().getName() + \".\" + fieldName + \"\\\"\");\n");
|
|
|
|
|
+
|
|
|
|
|
+ ret.append("\t\t}\n");
|
|
|
|
|
+ ret.append("\t}\n");
|
|
|
|
|
+ ret.append("}\n");
|
|
|
|
|
+
|
|
|
|
|
+ return ret.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|