enjoy 4.3 release ^_^
This commit is contained in:
181
src/main/java/com/jfinal/template/expr/ast/FastFieldGetter.java
Normal file
181
src/main/java/com/jfinal/template/expr/ast/FastFieldGetter.java
Normal file
@@ -0,0 +1,181 @@
|
||||
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<Class<?>, 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<javax.tools.JavaFileObject> collector) {
|
||||
if (outputCompileError) {
|
||||
super.outputCompileError(result, collector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ public class FieldGetters {
|
||||
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.getParameterTypes().length == 0) {
|
||||
if (method.getName().equals(getterName) && method.getParameterCount() == 0) {
|
||||
// if (MethodKit.isForbiddenMethod(getterName)) {
|
||||
// throw new RuntimeException("Forbidden method: " + getterName);
|
||||
// }
|
||||
@@ -115,7 +115,7 @@ public class FieldGetters {
|
||||
String isMethodName = "is" + StrKit.firstCharToUpperCase(fieldName);
|
||||
java.lang.reflect.Method[] methodArray = targetClass.getMethods();
|
||||
for (java.lang.reflect.Method method : methodArray) {
|
||||
if (method.getName().equals(isMethodName) && method.getParameterTypes().length == 0) {
|
||||
if (method.getName().equals(isMethodName) && method.getParameterCount() == 0) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (returnType == Boolean.class || returnType == boolean.class) {
|
||||
return new IsMethodFieldGetter(method);
|
||||
|
@@ -33,10 +33,14 @@ public abstract class FieldKeyBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置为官方提供的 FastFieldKeyBuilder 实现,性能更高
|
||||
* 开启 FastFieldKeyBuilder,性能更高
|
||||
*/
|
||||
public static void setToFastFieldKeyBuilder() {
|
||||
instance = new FastFieldKeyBuilder();
|
||||
public static void setFastFieldKeyBuilder(boolean enable) {
|
||||
if (enable) {
|
||||
instance = new FastFieldKeyBuilder();
|
||||
} else {
|
||||
instance = new StrictFieldKeyBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -140,6 +140,36 @@ public class FieldKit {
|
||||
public static void clearCache() {
|
||||
fieldGetterCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置极速模式
|
||||
*
|
||||
* 极速模式将生成代理对象来消除 java.lang.reflect.Method.invoke(...) 调用,
|
||||
* 性能提升 12.9%
|
||||
*/
|
||||
public static synchronized void setFastMode(boolean fastMode) {
|
||||
if (fastMode) {
|
||||
if ( !contains(FastFieldGetter.class) ) {
|
||||
addFieldGetterToFirst(new FastFieldGetter());
|
||||
}
|
||||
} else {
|
||||
if (contains(FastFieldGetter.class)) {
|
||||
removeFieldGetter(FastFieldGetter.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含某个 FieldGetter
|
||||
*/
|
||||
public static boolean contains(Class<? extends FieldGetter> fieldGetterClass) {
|
||||
for (FieldGetter fg : getters) {
|
||||
if (fg.getClass() == fieldGetterClass) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user