package business.cooperop.common.utils; /* ********************************************** * DATE PERSON REASON * 2020/9/4 FXY Created ********************************************** */ import com.esotericsoftware.reflectasm.MethodAccess; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; /** * 待重写 */ public class BeanUtilsV2 { /** * 通过 ASM反射 速度比 Spring BeanUtils.copyProperties(source,target) 快一倍 * 类型不同可以转换 * 大小写可以忽略 * 下划线 _ 被忽略 * fxy备注:需要操纵字节码,服务器没有性能瓶颈的情况下慎用! * * @param source 数据源 * @param target 目标是数据 * @param * @return */ public static T copyPropertiesASM(Object source, Object target) { MethodAccess sourceMethodAccess = CacheMethodAccess.getMethodAccess(source.getClass()); MethodAccess targetMethodAccess = CacheMethodAccess.getMethodAccess(target.getClass()); Map sourceGet = CacheAsmFiledMethod.getMethod("get", source.getClass()); Map targetSet = CacheAsmFiledMethod.getMethod("set", target.getClass()); CacheFieldMap.getFieldMap(target.getClass()).keySet().forEach((it) -> { String sourceIndex = sourceGet.get(it); if (sourceIndex != null) { Object value = sourceMethodAccess.invoke(source, sourceIndex); String setIndex = targetSet.get(it); targetMethodAccess.invoke(target, setIndex, value); } }); return (T) target; } /** * 模仿Spring中 BeanUtils.copyProperties(source,target) * 目前仅支持整形到布尔类型的单向转换 * 但是 * 大小写可以忽略 * 下划线 _ 被忽略 * * @param source * @param target * @param * @return */ public static T copyProperties(Object source, Object target) { Map sourceMap = CacheFieldMap.getFieldMap(source.getClass()); CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> { Field field = sourceMap.get(it.getName().toLowerCase().replace("_", "")); if (field != null) { it.setAccessible(true); field.setAccessible(true); try { if (field.getType() == Integer.class && it.getType() == Boolean.class) { it.set(target, (Integer) field.get(source) == 1 ? true : false); } else { it.set(target, field.get(source)); } } catch (IllegalAccessException e) { e.printStackTrace(); } finally { //及时关闭访问权限 field.setAccessible(false); it.setAccessible(false); } } }); return (T) target; } /** * @param source 源对象 * @param target 目标对象 * @param ignores 需要忽略的字段数组元素 * @param 返回赋了值的目标对象 * 目前不同类型之间的转换,仅支持整形向布尔类型的单向转换 * @return */ public static T copyProperties(Object source, Object target, String... ignores) { Map sourceMap = CacheFieldMap.getFieldMap(source.getClass(), ignores); CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> { Field field = sourceMap.get(it.getName().toLowerCase().replace("_", "")); if (field != null) { it.setAccessible(true); field.setAccessible(true); try { if (field.getType() == Integer.class && it.getType() == Boolean.class) { it.set(target, (Integer) field.get(source) == 1 ? true : false); } else { it.set(target, field.get(source)); } } catch (IllegalAccessException e) { e.printStackTrace(); } finally { field.setAccessible(false); it.setAccessible(false); } } }); return (T) target; } /** * Asm方式缓存变量域到map中,待优化 * 可以将加锁操作换做无阻塞的并发容器 */ private static class CacheAsmFiledMethod { private static Map> cacheGetMethod = new HashMap<>(); private static Map> cacheSetMethod = new HashMap<>(); private static Map getMethod(String type, Class clazz) { MethodAccess methodAccess = CacheMethodAccess.getMethodAccess(clazz); Map allFields = CacheFieldMap.getFieldMap(clazz); Map result = null; if (type.equals("get")) { result = cacheGetMethod.get(clazz.getName()); } else if (type.equals("set")) { result = cacheSetMethod.get(clazz.getName()); } if (result == null) { synchronized (CacheAsmFiledMethod.class) { if (result == null) { Map set = new HashMap<>(); Map get = new HashMap<>(); allFields.values().forEach((it) -> { //判断是否是静态 if (!Modifier.isStatic(it.getModifiers())) { //首字母大写 char[] f = it.getName().toCharArray(); f[0] -= 32; String fieldName = new String(f); get.put(fieldName.toLowerCase().replace("_", ""), "get" + fieldName); set.put(fieldName.toLowerCase().replace("_", ""), "set" + fieldName); } }); cacheGetMethod.put(clazz.getName(), get); cacheSetMethod.put(clazz.getName(), set); if (type.equals("get")) { result = cacheGetMethod.get(clazz.getName()); } else if (type.equals("set")) { result = cacheSetMethod.get(clazz.getName()); } } } } return result; } } /** * 缓存方法访问权限容器,加锁操作待优化 */ private static class CacheMethodAccess { private CacheMethodAccess() { } private static Map cache = new HashMap<>(); private static MethodAccess getMethodAccess(Class clazz) { MethodAccess result = cache.get(clazz.getName()); if (result == null) { synchronized (CacheMethodAccess.class) { if (result == null) { cache.put(clazz.getName(), MethodAccess.get(clazz)); result = cache.get(clazz.getName()); } } } return result; } } /** * 缓存所有域到map中,加锁操作待优化 */ private static class CacheFieldMap { private static Map> cacheMap = new HashMap<>(); private static Map getFieldMap(Class clazz) { Map result = cacheMap.get(clazz.getName()); if (result == null) { synchronized (CacheFieldMap.class) { if (result == null) { List allFields = getAllFields(clazz); Map fieldMap = allFields.stream().collect(Collectors.toMap(field -> field.getName().toLowerCase().replace("_", ""), Function.identity())); cacheMap.put(clazz.getName(), fieldMap); result = cacheMap.get(clazz.getName()); } } } return result; } /** * 每次反射完成后将数据存放在内存中 * * @param clazz * @param ignores * @return */ private static Map getFieldMap(Class clazz, String... ignores) { Map result = cacheMap.get(clazz.getName()); List list = Arrays.asList(ignores); if (result == null) { synchronized (CacheFieldMap.class) { if (result == null) { List allFields = getAllFields(clazz); Map fieldMap = allFields.stream().filter(a -> !(list.contains(a.getName()))).collect(Collectors.toMap(field -> field.getName().toLowerCase().replace("_", ""), Function.identity())); cacheMap.put(clazz.getName(), fieldMap); result = cacheMap.get(clazz.getName()); } } } return result; } } /** * 得到包括继承而来的所有域 * * @param clazz * @return */ private static List getAllFields(Class clazz) { List fieldList = new ArrayList<>(); while (clazz != null && !clazz.getName().toLowerCase().equals("java.lang.object")) { fieldList.addAll(Arrays.asList(clazz.getDeclaredFields())); clazz = clazz.getSuperclass(); } return fieldList; } }