核心原理:解析需要访问的类,将get和set方法使用ClassFile Api动态生成BeanVisitors,实现高性能动态属性访问和属性设置。本文基于Java 23,现在还是预览api,正式版可能会有所调整。
一、BeanVisitors实现属性操作
// 动态生成类的父类定义
@Getter
@RequiredArgsConstructor
public abstract class BeanVisitors {
/**
* bean字段对应的字段类型
*/
private final Map<String, BeanFieldType> beanFieldTypeMap;
/**
* 从指定实例中获取指定字段的属性值
*
* @param instances 实例
* @param key 字段名
* @return 字段值
*/
public abstract Object get(Object instances, String key);
/**
* 设置指定实例中对应字段的属性值
*
* @param instances 实例
* @param key 字段名
* @param value 字段值
*/
public abstract void put(Object instances, String key, Object value);
/**
* 获取字段类型
*
* @param key 字段名
* @return 字段类型
*/
public BeanFieldType beanFieldType(String key) {
return beanFieldTypeMap.get(key);
}
}
// 简单BeanMap实现
@RequiredArgsConstructor
public final class BeanMap {
/**
* 实例
*/
private final Object instance;
/**
* BeanVisitors
*/
private final BeanVisitors visitors;
/**
* @param key 字段名
* @return 属性值
*/
public Object get(String key) {
return visitors.get(instance, key);
}
/**
* @param key 字段名
* @param value 属性值
*/
public void put(String key, Object value) {
visitors.put(instance, key, value);
}
/**
* 将属性copy到对应对象
*
* @param target 目标对象
* @return target
*/
public <R> R copyTo(R target) {
return BeanCopier.copy(instance, target);
}
}
// 字段类型
public class BeanFieldType {
/**
* set方法的参数类型
*/
Class<?> paramClass;
/**
* get方法的返回类型
*/
Class<?> returnClass;
/**
* 原始类型转换成包装类
*
* @param paramClass 参数类型
*/
void setParamClass(Class<?> paramClass) {
this.paramClass = toWrapperClass(paramClass);
}
/**
* 原始类型转换成包装类型
*
* @param returnClass 返回类型
*/
void setReturnClass(Class<?> returnClass) {
this.returnClass = toWrapperClass(returnClass);
}
/**
* 将基本类型转换成包装类(统一使用包装类处理)
*
* @param type 类型
* @return 包装类
*/
private Class<?> toWrapperClass(Class<?> type) {
if (type == int.class) {
return Integer.class;
} else if (type == long.class) {
return Long.class;
} else if (type == float.class) {
return Float.class;
} else if (type == double.class) {
return Double.class;
} else if (type == short.class) {
return Short.class;
} else if (type == byte.class) {
return Byte.class;
} else if (type == char.class) {
return Character.class;
} else if (type == boolean.class) {
return Boolean.class;
}
return type;
}
}
@SuppressWarnings("preview")
public abstract class BeanVisitorFactory {
/**
* class对应的访问器缓存(使用软引用来淘汰缓存)
*/
private static final Map<Class<?>, KeySoftReference> BEAN_MAP_CACHE = new ConcurrentHashMap<>();
/**
* 引用队列
*/
private static final ReferenceQueue<BeanVisitors> KEY_REFERENCE_QUEUE = new ReferenceQueue<>();
static {
// 开启线程清除无效缓存
Thread beanVisitorFactoryClean = new Thread(() -> {
try {
while (true) {
// 删除map中缓存的无效对象
KeySoftReference remove = (KeySoftReference) KEY_REFERENCE_QUEUE.remove();
BEAN_MAP_CACHE.remove(remove.key, remove);
}
} catch (InterruptedException e) {
// ignore
}
}, "BeanVisitorFactoryClean");
beanVisitorFactoryClean.setDaemon(true);
beanVisitorFactoryClean.start();
}
/**
* 根据指定实例创建beanMap
*
* @param instance 实例
* @return beanMap
*/
public static BeanMap createBeanMap(Object instance) {
BeanVisitors visitor = createBeanVisitor(instance.getClass());
return new BeanMap(instance, visitor);
}
/**
* 创建BeanVisitors
*
* @param clazz class
* @return BeanVisitors
*/
public static BeanVisitors createBeanVisitor(Class<?> clazz) {
return BEAN_MAP_CACHE.compute(clazz, (entityClass, oldReference) -> {
if (oldReference != null && oldReference.get() != null) {
return oldReference;
}
// get set分别处理 支持只存在其中一种方法的情况
GetSetMethod getSetMethod = methodInfo(entityClass);
String entityClassName = entityClass.getName();
// 动态生成的class类名
String beanVisitorsClassName = entityClassName + "$$BeanVisitors";
byte[] beanVisitorsCode = ClassFile.of().build(ClassDesc.of(beanVisitorsClassName), classBuilder -> {
// 设置类PUBLIC和SYNTHETIC
classBuilder.withFlags(AccessFlag.PUBLIC, AccessFlag.SYNTHETIC);
// 设置父类
ClassDesc superClassDesc = BeanVisitors.class.describeConstable().orElseThrow();
classBuilder.withSuperclass(superClassDesc);
// 实现构造函数
classBuilder.withMethodBody(ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Map),
ClassFile.ACC_PUBLIC, codeBuilder -> {
// 加载this
codeBuilder.aload(codeBuilder.receiverSlot());
// 加载第一个参数
codeBuilder.aload(codeBuilder.parameterSlot(0));
// 执行父类构造方法
MethodTypeDesc voidMapMethodTypeDesc = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Map);
codeBuilder.invokespecial(superClassDesc, ConstantDescs.INIT_NAME, voidMapMethodTypeDesc);
// return
codeBuilder.return_();
});
ClassDesc entityDesc = ClassDesc.of(entityClassName);
// 实现get方法
classBuilder.withMethodBody("get", MethodTypeDesc.of(ConstantDescs.CD_Object, ConstantDescs.CD_Object,
ConstantDescs.CD_String), ClassFile.ACC_PUBLIC,
codeBuilder -> buildCode(entityDesc, codeBuilder, 3, getSetMethod.hashGetMap,
((blockCodeBuilder, getMethod) -> {
// 调用对应实体的getXX方法
blockCodeBuilder.invokevirtual(entityDesc, getMethod.methodName, MethodTypeDesc.of(getMethod.returnType));
// 将原型类包装成包装类
box(codeBuilder, getMethod.returnType);
// return obj
blockCodeBuilder.areturn();
})));
// 实现put方法
classBuilder.withMethodBody("put", MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Object,
ConstantDescs.CD_String, ConstantDescs.CD_Object), ClassFile.ACC_PUBLIC,
codeBuilder -> buildCode(entityDesc, codeBuilder, 4, getSetMethod.hashSetMap,
((blockCodeBuilder, setMethod) -> {
// 加载第二个参数
blockCodeBuilder.aload(blockCodeBuilder.parameterSlot(2));
// 类型转换
checkCast(blockCodeBuilder, setMethod.paramType);
// 执行对应的setXX方法
blockCodeBuilder.invokevirtual(entityDesc, setMethod.methodName, MethodTypeDesc.of(setMethod.returnType, setMethod.paramType));
// return
blockCodeBuilder.return_();
})));
});
try {
// 定义隐藏类
Class<?> beanVisitorsClass = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup())
.defineHiddenClass(beanVisitorsCode, false).lookupClass();
// 获取构造方法
Constructor<?> declaredConstructor = beanVisitorsClass.getDeclaredConstructor(Map.class);
// 实例化
return new KeySoftReference(entityClass, (BeanVisitors) declaredConstructor
.newInstance(Collections.unmodifiableMap(getSetMethod.fieldTypeMap)));
} catch (IllegalAccessException | NoSuchMethodException | InstantiationException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
}).get();
}
/**
* 构建get或者put方法的方法体
* 字段生成的代码逻辑:
* <pre>
* {@code
* switch (字段名.hashCode) {
* case 1:
* if (key.equals(fieldName)) {
* 实例.(getXX() | setXX())
* return;
* }
* break;
* }
* }
* </pre>
*
* @param entityDesc 实例描述
* @param codeBuilder codeBuilder
* @param entityStoreIdx 转换类型后实例store的索引
* @param switchMap 构建switch表达式的map
* @param methodConsumer get和put分别的额外逻辑
*/
private static <METHOD extends MethodInfo> void buildCode(ClassDesc entityDesc, CodeBuilder codeBuilder, int entityStoreIdx, Map<Integer, List<METHOD>> switchMap, BiConsumer<CodeBuilder.BlockCodeBuilder, METHOD> methodConsumer) {
// 存在的时候构建switch
if (!switchMap.isEmpty()) {
// 加载参数0
codeBuilder.aload(codeBuilder.parameterSlot(0));
// 类型转换
codeBuilder.checkcast(entityDesc);
// store
codeBuilder.astore(entityStoreIdx);
// 加载参数1
codeBuilder.aload(codeBuilder.parameterSlot(1));
// 执行hashcode方法
codeBuilder.invokevirtual(ConstantDescs.CD_String, "hashCode", MethodTypeDesc.of(ConstantDescs.CD_int));
int size = switchMap.size();
// 初始化每个switch对应label 标记每个case的位置
Map<Integer, Label> hashLabel = HashMap.newHashMap(size);
List<SwitchCase> switchCases = new ArrayList<>(size);
for (Integer hashCode : switchMap.keySet()) {
Label label = codeBuilder.newLabel();
hashLabel.put(hashCode, label);
// case hashCode(类中字段名的)
switchCases.add(SwitchCase.of(hashCode, label));
}
// switch结束label
Label switchEndLabel = codeBuilder.newLabel();
// 创建switch
codeBuilder.lookupswitch(switchEndLabel, switchCases);
for (Map.Entry<Integer, List<METHOD>> hashMethodMap : switchMap.entrySet()) {
// block代码块
codeBuilder.block(blockCodeBuilder -> {
Integer hashCode = hashMethodMap.getKey();
// 获取之前初始化的label 绑定label
blockCodeBuilder.labelBinding(hashLabel.get(hashCode));
// 处理每一个get或者set方法
for (METHOD method : hashMethodMap.getValue()) {
// 加载第一个方法参数
blockCodeBuilder.aload(blockCodeBuilder.parameterSlot(1));
// 加载字段名常量
blockCodeBuilder.ldc(method.fieldName());
// 执行equals方法 if(key.equals("xx"))
blockCodeBuilder.invokevirtual(ConstantDescs.CD_String, "equals", MethodTypeDesc
.of(ConstantDescs.CD_boolean, ConstantDescs.CD_Object));
// 不满足直接跳转到switch结束
blockCodeBuilder.ifeq(switchEndLabel);
// 加载之前转换后的实体
blockCodeBuilder.aload(entityStoreIdx);
// 执行get和put方法的不同逻辑
methodConsumer.accept(blockCodeBuilder, method);
}
});
}
// switch结束
codeBuilder.labelBinding(switchEndLabel);
}
// 没有找到匹配的 抛出异常
ClassDesc exClassDesc = UnsupportedOperationException.class.describeConstable().orElseThrow();
// new UnsupportedOperationException
codeBuilder.new_(exClassDesc);
// 将操作数栈上的UnsupportedOperationException复制一份
codeBuilder.dup();
// 执行构造方法
codeBuilder.invokespecial(exClassDesc, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void);
// 抛出异常
codeBuilder.athrow();
}
/**
* 获取实体类中的get和set方法信息
*
* @param entityClass 实体类
* @return get和set的方法信息
*/
private static GetSetMethod methodInfo(Class<?> entityClass) {
Map<Integer, List<GetMethod>> hashGetMethodMap = new HashMap<>();
Map<Integer, List<SetMethod>> hashSetMethodMap = new HashMap<>();
Map<String, BeanFieldType> fieldTypeMap = new HashMap<>();
GetSetMethod getSetMethod = new GetSetMethod(hashGetMethodMap, hashSetMethodMap, fieldTypeMap);
while (entityClass != Object.class) {
Method[] declaredMethods = entityClass.getDeclaredMethods();
for (Method method : declaredMethods) {
int modifiers = method.getModifiers();
// public且不是静态方法
if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) {
continue;
}
String name = method.getName();
Class<?> returnType = method.getReturnType();
int parameterCount = method.getParameterCount();
int subIdx;
boolean isGetter = name.startsWith("get");
if ((isGetter && parameterCount == 0 && returnType != void.class) ||
(name.startsWith("set") && parameterCount == 1)) {
// get和set方法截取三个字符
subIdx = 3;
} else if (name.startsWith("is") && parameterCount == 0 && returnType != void.class) {
// is截取两个字符
isGetter = true;
subIdx = 2;
} else {
continue;
}
String standardFieldName = standardFieldName(name, subIdx);
if (standardFieldName == null) {
continue;
}
int hashCode = standardFieldName.hashCode();
BeanFieldType beanFieldType = fieldTypeMap.computeIfAbsent(standardFieldName, _ -> new BeanFieldType());
if (isGetter) {
// 添加Get方法信息
GetMethod getMethod = new GetMethod(name, standardFieldName, returnType.describeConstable().orElseThrow());
hashGetMethodMap.computeIfAbsent(hashCode, _ -> new ArrayList<>()).add(getMethod);
beanFieldType.setReturnClass(returnType);
} else {
// 添加Set方法信息
Class<?> parameterType = method.getParameterTypes()[0];
SetMethod setMethod = new SetMethod(name, standardFieldName, parameterType.describeConstable().orElseThrow(),
returnType.describeConstable().orElseThrow());
hashSetMethodMap.computeIfAbsent(hashCode, _ -> new ArrayList<>()).add(setMethod);
beanFieldType.setParamClass(parameterType);
}
}
entityClass = entityClass.getSuperclass();
}
return getSetMethod;
}
/**
* 截取后第一个字符小写的不符合规则
* 第二个字符大写直接使用方法名,否则将第一个字符改为小写
*
* @param methodName 方法名
* @param subIdx 截取index
* @return 规范字段名
*/
private static String standardFieldName(String methodName, int subIdx) {
int length = methodName.length();
if (length <= subIdx) {
return null;
}
String fieldName = methodName.substring(subIdx, length);
if (fieldName.length() == 1) {
return fieldName.toLowerCase();
}
char firstChar = fieldName.charAt(0);
if (Character.isLowerCase(firstChar)) {
return null;
}
char secondChar = fieldName.charAt(1);
if (Character.isUpperCase(secondChar)) {
return fieldName;
}
return Character.toLowerCase(firstChar) + fieldName.substring(1);
}
/**
* 类型转换,转换基础类型时,先将Object转换成对应包装类,在调用对应方法拆箱
*
* @param codeBuilder codeBuilder
* @param typeDesc 需要的类型
*/
private static void checkCast(CodeBuilder codeBuilder, ClassDesc typeDesc) {
// 调用对应的方法进行拆箱
if (typeDesc == ConstantDescs.CD_int) {
codeBuilder.checkcast(ConstantDescs.CD_Integer);
codeBuilder.invokevirtual(ConstantDescs.CD_Integer, "intValue", MethodTypeDesc.of(ConstantDescs.CD_int));
} else if (typeDesc == ConstantDescs.CD_long) {
codeBuilder.checkcast(ConstantDescs.CD_Long);
codeBuilder.invokevirtual(ConstantDescs.CD_Long, "longValue", MethodTypeDesc.of(ConstantDescs.CD_long));
} else if (typeDesc == ConstantDescs.CD_float) {
codeBuilder.checkcast(ConstantDescs.CD_Float);
codeBuilder.invokevirtual(ConstantDescs.CD_Float, "floatValue", MethodTypeDesc.of(ConstantDescs.CD_float));
} else if (typeDesc == ConstantDescs.CD_double) {
codeBuilder.checkcast(ConstantDescs.CD_Double);
codeBuilder.invokevirtual(ConstantDescs.CD_Double, "doubleValue", MethodTypeDesc.of(ConstantDescs.CD_double));
} else if (typeDesc == ConstantDescs.CD_short) {
codeBuilder.checkcast(ConstantDescs.CD_Short);
codeBuilder.invokevirtual(ConstantDescs.CD_Short, "shortValue", MethodTypeDesc.of(ConstantDescs.CD_short));
} else if (typeDesc == ConstantDescs.CD_byte) {
codeBuilder.checkcast(ConstantDescs.CD_Byte);
codeBuilder.invokevirtual(ConstantDescs.CD_Byte, "byteValue", MethodTypeDesc.of(ConstantDescs.CD_byte));
} else if (typeDesc == ConstantDescs.CD_char) {
codeBuilder.checkcast(ConstantDescs.CD_Character);
codeBuilder.invokevirtual(ConstantDescs.CD_Character, "charValue", MethodTypeDesc.of(ConstantDescs.CD_char));
} else if (typeDesc == ConstantDescs.CD_boolean) {
codeBuilder.checkcast(ConstantDescs.CD_Boolean);
codeBuilder.invokevirtual(ConstantDescs.CD_Boolean, "booleanValue", MethodTypeDesc.of(ConstantDescs.CD_boolean));
} else {
// 引用类型直接转换
codeBuilder.checkcast(typeDesc);
}
}
/**
* 将基本类型进行装箱
*
* @param codeBuilder codeBuilder
* @param typeDesc 需要的类型
*/
private static void box(CodeBuilder codeBuilder, ClassDesc typeDesc) {
if (!typeDesc.isPrimitive()) {
return;
}
// 调用对应的valueOf方法进行装箱
if (typeDesc == ConstantDescs.CD_int) {
codeBuilder.invokestatic(ConstantDescs.CD_Integer, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Integer, ConstantDescs.CD_int));
} else if (typeDesc == ConstantDescs.CD_long) {
codeBuilder.invokestatic(ConstantDescs.CD_Long, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Long, ConstantDescs.CD_long));
} else if (typeDesc == ConstantDescs.CD_float) {
codeBuilder.invokestatic(ConstantDescs.CD_Float, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Float, ConstantDescs.CD_float));
} else if (typeDesc == ConstantDescs.CD_double) {
codeBuilder.invokestatic(ConstantDescs.CD_Double, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Double, ConstantDescs.CD_double));
} else if (typeDesc == ConstantDescs.CD_short) {
codeBuilder.invokestatic(ConstantDescs.CD_Short, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Short, ConstantDescs.CD_short));
} else if (typeDesc == ConstantDescs.CD_byte) {
codeBuilder.invokestatic(ConstantDescs.CD_Byte, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Byte, ConstantDescs.CD_byte));
} else if (typeDesc == ConstantDescs.CD_char) {
codeBuilder.invokestatic(ConstantDescs.CD_Character, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Character, ConstantDescs.CD_char));
} else if (typeDesc == ConstantDescs.CD_boolean) {
codeBuilder.invokestatic(ConstantDescs.CD_Boolean, "valueOf", MethodTypeDesc.of(ConstantDescs.CD_Boolean, ConstantDescs.CD_boolean));
} else {
throw new UnsupportedOperationException("box not supported");
}
}
/**
* Get和Set方法信息
*
* @param hashGetMap hashCode对应的Get方法
* @param hashSetMap hashCode对应Set方法
* @param fieldTypeMap 字段名对应的类型
*/
record GetSetMethod(Map<Integer, List<GetMethod>> hashGetMap, Map<Integer, List<SetMethod>> hashSetMap,
Map<String, BeanFieldType> fieldTypeMap) {
}
/**
* 字段名
*/
interface MethodInfo {
String fieldName();
}
/**
* Set方法信息
*
* @param methodName 方法名字
* @param fieldName 字段名字
* @param paramType 参数类型
* @param returnType 返回值类型
*/
record SetMethod(String methodName, String fieldName, ClassDesc paramType,
ClassDesc returnType) implements MethodInfo {
}
/**
* Get方法信息
*
* @param methodName 方法名字
* @param fieldName 字段名字
* @param returnType 返回值类型
*/
record GetMethod(String methodName, String fieldName, ClassDesc returnType) implements MethodInfo {
}
/**
* 记录class的软引用,方便从缓存中删除无效的数据
*/
static class KeySoftReference extends SoftReference<BeanVisitors> {
/**
* 缓存key
*/
final Class<?> key;
/**
* @param key key
* @param referent BeanVisitors
*/
public KeySoftReference(Class<?> key, BeanVisitors referent) {
super(referent, KEY_REFERENCE_QUEUE);
this.key = key;
}
}
}
二、BeanCopier实现Bean属性复制
public interface BeanCopier {
/**
* source对象中的属性copy到target
*
* @param source 源对象
* @param target 目标对象
* @return target
*/
static <R> R copy(Object source, R target) {
return copy(source, target, null);
}
/**
* source对象中的属性copy到target,source和target中字段名字相同,类型不同时可以自定义转换规则
*
* @param source 源对象
* @param target 目标对象
* @param converter 自定义类型转换器
* @return target
*/
static <R> R copy(Object source, R target, TypeConverter converter) {
// 分别创建BeanVisitors
BeanVisitors sourceVisitors = BeanVisitorFactory.createBeanVisitor(source.getClass());
BeanVisitors targetVisitors = BeanVisitorFactory.createBeanVisitor(target.getClass());
// 遍历源对象的字段信息
for (Map.Entry<String, BeanFieldType> fieldTypeEntry : sourceVisitors.getBeanFieldTypeMap().entrySet()) {
BeanFieldType getBeanFieldType = fieldTypeEntry.getValue();
Class<?> returnClass = getBeanFieldType.returnClass;
if (returnClass == null) {
continue;
}
// 查找目标对象字段信息
String field = fieldTypeEntry.getKey();
BeanFieldType setBeanFieldType = targetVisitors.beanFieldType(field);
if (setBeanFieldType == null || setBeanFieldType.paramClass == null) {
continue;
}
Object fieldValue = null;
if (returnClass == setBeanFieldType.paramClass) {
// 类型相同时,直接获取
fieldValue = sourceVisitors.get(source, field);
} else if (converter != null) {
// 类型不同 存在转换器时 进行转换
fieldValue = sourceVisitors.get(source, field);
if (fieldValue != null) {
fieldValue = converter.convert(fieldValue, setBeanFieldType.paramClass);
}
}
if (fieldValue != null) {
// 填充
targetVisitors.put(target, field, fieldValue);
}
}
return target;
}
}
三、使用示例
public class TestBean {
public static void main(String[] args) {
Source source = new Source(1, "test");
BeanMap beanMap = BeanVisitorFactory.createBeanMap(source);
System.out.println("beanMap.get(\"i\") = " + beanMap.get("i"));
beanMap.put("name", "hello");
System.out.println("beanMap.get(\"name\") = " + beanMap.get("name"));
System.out.println("beanMap.copyTo(new Target()) = " + beanMap.copyTo(new Target()));
System.out.println("BeanCopier.copy(source, new Target()) = " + BeanCopier.copy(source, new Target()));
}
@Data
@AllArgsConstructor
static class Source {
private int i;
private String name;
}
@Data
static class Target {
private Integer i;
private String name;
}
}