133 lines
3.9 KiB
Java
133 lines
3.9 KiB
Java
/**
|
||
* Copyright (c) 2011-2019, James Zhan 詹波 (jfinal@126.com).
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
package com.jfinal.template.expr.ast;
|
||
|
||
/**
|
||
* FieldKeyBuilder
|
||
*
|
||
* 用于生成缓存 FieldGetter 的 key
|
||
*/
|
||
public abstract class FieldKeyBuilder {
|
||
|
||
public abstract Object getFieldKey(Class<?> targetClass, long fieldFnv1a64Hash);
|
||
|
||
// 假定是超大规模项目,并且假定其 Map/Model/Record + field 组合数量超级庞大,默认使用 StrictFieldKeyBuilder
|
||
static FieldKeyBuilder instance = new StrictFieldKeyBuilder();
|
||
|
||
public static FieldKeyBuilder getInstance() {
|
||
return instance;
|
||
}
|
||
|
||
/**
|
||
* 开启 FastFieldKeyBuilder,性能更高
|
||
*/
|
||
public static void setFastFieldKeyBuilder(boolean enable) {
|
||
if (enable) {
|
||
instance = new FastFieldKeyBuilder();
|
||
} else {
|
||
instance = new StrictFieldKeyBuilder();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置为自定义 FieldKeyBuilder
|
||
*/
|
||
public static void setFieldKeyBuilder(FieldKeyBuilder fieldKeyBuilder) {
|
||
if (fieldKeyBuilder == null) {
|
||
throw new IllegalArgumentException("fieldKeyBuilder can not be null");
|
||
}
|
||
instance = fieldKeyBuilder;
|
||
}
|
||
|
||
// ------------------------------------------------------------------------
|
||
|
||
/**
|
||
* FastFieldKeyBuilder
|
||
*/
|
||
public static class FastFieldKeyBuilder extends FieldKeyBuilder {
|
||
public Object getFieldKey(Class<?> targetClass, long fieldFnv1a64Hash) {
|
||
return targetClass.getName().hashCode() ^ fieldFnv1a64Hash;
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------------------
|
||
|
||
/**
|
||
* StrictFieldKeyBuilder
|
||
*/
|
||
public static class StrictFieldKeyBuilder extends FieldKeyBuilder {
|
||
public Object getFieldKey(Class<?> targetClass, long fieldFnv1a64Hash) {
|
||
return new FieldKey(targetClass.getName().hashCode(), fieldFnv1a64Hash);
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------------------
|
||
|
||
/**
|
||
* FieldKey
|
||
*
|
||
* FieldKey 用于封装 targetClass、fieldName 这两部分的 hash 值,
|
||
* 确保不会出现 key 值碰撞
|
||
*
|
||
* 这两部分 hash 值在不同 class 与 field 的组合下出现碰撞的
|
||
* 概率完全可以忽略不计
|
||
*
|
||
* 备忘:
|
||
* 可以考虑用 ThreadLocal 重用 FieldKey 对象,但要注意放入 Map fieldGetterCache
|
||
* 中的 FieldKey 对象需要 clone 出来,确保线程安全。由于 FieldKey 占用空间不大,
|
||
* 所以 ThreadLocal 方案大概率并无优势,从 ThreadLocal 中获取数据时,除了耗时也无法
|
||
* 避免创建对象
|
||
*/
|
||
public static class FieldKey {
|
||
|
||
final long classHash;
|
||
final long fieldHash;
|
||
|
||
public FieldKey(long classHash, long fieldHash) {
|
||
this.classHash = classHash;
|
||
this.fieldHash = fieldHash;
|
||
}
|
||
|
||
public int hashCode() {
|
||
return (int)(classHash ^ fieldHash);
|
||
}
|
||
|
||
/**
|
||
* FieldKey 的核心价值在于此 equals 方法通过比较两部分 hash 值,避免超大规模场景下可能的 key 值碰撞
|
||
*
|
||
* 不必判断 if (fieldKey instanceof FieldKey),因为所有 key 类型必须要相同
|
||
* 不必判断 if (this == fieldKey),因为每次用于取值的 FieldKey 都是新建的
|
||
*/
|
||
public boolean equals(Object fieldKey) {
|
||
FieldKey fk = (FieldKey)fieldKey;
|
||
return classHash == fk.classHash && fieldHash == fk.fieldHash;
|
||
}
|
||
|
||
public String toString() {
|
||
return "classHash = " + classHash + "\nfieldHash = " + fieldHash;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|