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; /** * 使用 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, Proxy> cache = new ConcurrentHashMap<>(512, 0.25F); protected static boolean outputCompileError = false; 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 (Throwable 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(); } } // --------- public static void setOutputCompileError(boolean outputCompileError) { FastFieldGetter.outputCompileError = outputCompileError; } /** * 代理编译器 */ static class ProxyCompiler extends com.jfinal.proxy.ProxyCompiler { @Override protected void outputCompileError(Boolean result, javax.tools.DiagnosticCollector collector) { if (outputCompileError) { super.outputCompileError(result, collector); } } } }