Browse Source

jfinal 4.3

James 6 years ago
parent
commit
c5520e9370

+ 16 - 0
src/main/java/com/jfinal/template/Engine.java

@@ -559,6 +559,22 @@ public class Engine {
 	public static void setToFastFieldKeyBuilder() {
 		FieldKeyBuilder.setToFastFieldKeyBuilder();
 	}
+	
+	/**
+	 * 设置极速模式
+	 * 
+	 * 极速模式将生成代理对象来消除 java.lang.reflect.Method.invoke(...) 调用,
+	 * 性能提升 12.9%
+	 */
+	public static void setFastMode(boolean fastMode) {
+		if (fastMode) {
+			addFieldGetterToFirst(new com.jfinal.template.expr.ast.FastFieldGetter());
+			FieldKeyBuilder.setToFastFieldKeyBuilder();
+		} else {
+			removeFieldGetter(com.jfinal.template.expr.ast.FastFieldGetter.class);
+			FieldKeyBuilder.setFieldKeyBuilder(new com.jfinal.template.expr.ast.FieldKeyBuilder.StrictFieldKeyBuilder());
+		}
+	}
 }
 
 

+ 162 - 0
src/main/java/com/jfinal/template/expr/ast/FastFieldGetter.java

@@ -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();
+		}	
+	}
+}
+