import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.*;
import net.bytebuddy.matcher.ElementMatchers;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 动态代理工厂类,用于生成动态代理类。
*/
public class DynamicProxyFactory {
private static final ConcurrentHashMap<String, Class<?>> classCache = new ConcurrentHashMap<>();
/**
* 获取动态生成的子类,如果已经生成过则直接从缓存中返回
*
* @param originalClass 原始类,即要继承的类
* @param fieldClassMap 字段类型映射表,key为字段名,value为字段对应的类类型
* @param <T> 原始类的类型参数
* @return Class<?> 动态生成的子类
*/
public static <T> Class<? extends T> getCachedDynamicSubclass(Class<T> originalClass, Map<String, Class<?>> fieldClassMap) {
String key = generateCacheKey(originalClass, fieldClassMap);
return (Class<? extends T>) classCache.computeIfAbsent(key, item -> createDynamicSubclass(originalClass, fieldClassMap));
}
public void set(Object obj, String fieldName, Object value) {
try {
obj.getClass().getMethod("set" + capitalizeFirstLetter(fieldName), value.getClass()).invoke(obj, value);
} catch (Exception e) {
throw new IllegalStateException("设置字段失败", e);
}
}
public void get(Object obj, String fieldName) {
try {
obj.getClass().getMethod("get" + capitalizeFirstLetter(fieldName)).invoke(obj);
} catch (Exception e) {
throw new IllegalStateException("获取字段失败", e);
}
}
/**
* 生成用于缓存的键。
*
* @param originalClass 原始类,即要继承的类
* @param fieldClassMap 字段类型映射表,key为字段名,value为字段对应的类类型
* @param <T> 原始类的类型参数
* @return 生成的缓存键字符串
*/
private static <T> String generateCacheKey(Class<T> originalClass, Map<String, Class<?>> fieldClassMap) {
StringBuilder sb = new StringBuilder(originalClass.getName());
sb.append("-");
fieldClassMap.keySet().forEach(sb::append);
return sb.toString();
}
/**
* 创建一个动态生成的子类。
*
* @param originalClass 原始类,即要继承的类
* @param fieldClassMap 字段类型映射表,key为字段名,value为字段对应的类类型
* @param <T> 原始类的类型参数
* @return 动态生成的子类的Class对象
* @throws IllegalStateException 如果在创建动态子类时发生错误
*/
private static <T> Class<?> createDynamicSubclass(Class<T> originalClass, Map<String, Class<?>> fieldClassMap) {
DynamicType.Builder<T> subclass = new ByteBuddy()
.subclass(originalClass);
for (Map.Entry<String, Class<?>> entry : fieldClassMap.entrySet()) {
String field = entry.getKey();
Class<?> fieldClass = entry.getValue();
subclass = defineFieldAndAccessors(subclass, field, fieldClass);
}
subclass = defineCommonMethods(subclass);
return subclass.make()
.load(Thread.currentThread().getContextClassLoader())
.getLoaded();
}
/**
* 为给定的动态类型构建器定义字段和对应的访问器方法。
*
* @param builder 动态类型构建器
* @param fieldName 字段名
* @param fieldClass 字段的类类型
* @param <T> 动态类型构建器对应的泛型类型
* @return 返回更新后的动态类型构建器
*/
private static <T> DynamicType.Builder<T> defineFieldAndAccessors(DynamicType.Builder<T> builder, String fieldName, Class<?> fieldClass) {
return builder.defineField(fieldName, fieldClass, Visibility.PRIVATE)
.defineMethod("get" + capitalizeFirstLetter(fieldName), fieldClass, Visibility.PUBLIC)
.intercept(FieldAccessor.ofField(fieldName))
.defineMethod("set" + capitalizeFirstLetter(fieldName), void.class, Visibility.PUBLIC)
.withParameter(fieldClass)
.intercept(FieldAccessor.ofField(fieldName));
}
/**
* 为给定的动态类型构建器定义通用方法:toString、hashCode和equals,并返回更新后的构建器。
*
* @param builder 动态类型构建器
* @param <T> 动态类型构建器对应的泛型类型
* @return 更新后的动态类型构建器
*/
private static <T> DynamicType.Builder<T> defineCommonMethods(DynamicType.Builder<T> builder) {
return builder.method(ElementMatchers.named("toString"))
.intercept(ToStringMethod.prefixedBySimpleClassName())
.method(ElementMatchers.named("hashCode"))
.intercept(HashCodeMethod.usingDefaultOffset())
.method(ElementMatchers.named("equals"))
.intercept(EqualsMethod.requiringSuperClassEquality());
}
/**
* 将字符串的首字母转换为大写,其余字母保持不变。
*
* @param str 要转换的字符串
* @return 转换后的字符串,如果输入字符串为null或空字符串,则返回原字符串
*/
private static String capitalizeFirstLetter(String str) {
if(str == null || str.isEmpty()) {
return str;
} else {
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
}
}
花了一下午的时间写了一个 动态代理工厂类,感觉没有什么应用场景,我需要解决的问题 也没有用它解决,想发给大家看看是否有需要用到的,或者是否有需要改进。