对象属性拷贝工具类大全==>Bean的属性拷贝从此不用愁
大家在做java开发时,肯定会遇到api层参数对象传递给服务层,
或者把service层的对象传递给dao层,他们之间又不是同一个类型对象,
但字段又是一样,如果还是用普通的get、set方式来处理话,比较繁琐,.... 那么你来跟我学....."天下武功,唯快不破"===>要的就是快....
1.使用get/set不用说了,字段一多脑壳大....
2.BeanCopier 使用了cglib的修改字节码,真的是动态Read Writer getter/setter 快的一逼啊 源码过于简单 直接上代码 我使用的最基本的,大家可以自定义Converter,定以后完全按照Converter转换
需要注意的是:
* 1.当源类和目标类的属性名称、类型都相同,拷贝结果棒棒哒。
* 2.当源对象和目标对象的属性名称相同、类型不同,那么名称相同而类型不同的属性不会被拷贝。另外注意,原始类型(int,short,char)和 他们的包装类型,在这里都被当成了不同类型。因此不会被拷贝。
* 3.源类或目标类的setter比getter少,拷贝没问题,此时setter多余,但是不会报错。
* 4.源类和目标类有相同的属性(两者的getter都存在),但是目标类的setter不存在, 此时会抛出NullPointerException(这个在高版本bug已经修改测试通过,我使用的49.0)
/**
* @author LiJing
* @ClassName: BeanCopyUtils
* @Description: 基于BeanCopier的属性拷贝
* @date 2019/4/17 9:15 * * 凡是和反射相关的操作,基本都是低性能的。凡是和字节码相关的操作,基本都是高性能的。
* <p/>
*/
@Slf4j
public class BeanCopyUtils { /**
* 创建过的BeanCopier实例放到缓存中,下次可以直接获取,提升性能
*/
private static final Map<String, BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<>(); /**
* 该方法没有自定义Converter,简单进行常规属性拷贝
*
* @param srcObj 源对象
* @param destObj 目标对象
*/
public static void copy(final @NotNull Object srcObj, final @NotNull Object destObj) {
String key = genKey(srcObj.getClass(), destObj.getClass());
BeanCopier copier;
if (!BEAN_COPIERS.containsKey(key)) {
copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);
BEAN_COPIERS.put(key, copier);
} else {
copier = BEAN_COPIERS.get(key);
}
copier.copy(srcObj, destObj, null);
} private static String genKey(Class<?> srcClazz, Class<?> destClazz) {
return srcClazz.getName() + destClazz.getName();
}
}
3.接下来再来玩一个org.springframework.beans.BeanUtils,这个比较骚,使用反射,反射就比较慢了,要加载字节码,反编译,再实例化,再映射属性.....来来上二斤代码,先吃着 有用的地方不多大家看着用哈<copyProperties>其实有这个方法就够了
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; /**
* @author LiJing
* @ClassName: BeanUtils
* @Description: 属性拷贝工具类
* @date 2018/4/10 11:54
*/
@Slf4j
public class MyBeanUtils extends BeanUtils { /**
* 从org.springframework.beans.BeanUtils类中直接复制过来
*
* @param source
* @param target
* @throws BeansException
*/
public static void copyProperties(Object source, Object target) throws BeansException {
copyProperties(source, target, null, (String[]) null);
} /**
* 从org.springframework.beans.BeanUtils类中直接复制过来,修改部分代码,不为null才复制
*
* @param source
* @param target
* @param editable
* @param ignoreProperties
* @throws BeansException
*/
private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
throws BeansException { Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null"); Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
"] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
// 判断被复制的属性是否为null, 如果不为null才复制
if (value != null) {
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
} catch (Throwable ex) {
throw new FatalBeanException(
"不能拷贝属性 '" + targetPd.getName() + "' 从原对象给目标对象,详细原因见:", ex);
}
}
}
}
}
} /**
* 构造函数.
*/
public MyBeanUtils() {
throw new RuntimeException("this is a util class,can not instance");
}
}
4.还有很多属性拷贝的方法例如org.apache.commons.beanutils.BeanUtils的copyProperties(Object dest, Object src)这里不举例了 类似于Spring的属性拷贝
5.还有使用easymapper来进行对象映射,但在项目中存在不稳性,偶尔出现映射不上的问题,会报异常com.baidu.unbiz.easymapper.exception.MappingException,大家可自行研究
其实有很多种方法进行属性拷贝的,例如dozer等等 下面看下测试性能吧:以:万级进行测试,我觉得Cglib太给力了.可以在遇到属性拷贝瓶颈时考虑.当然他们各有优点哈,功能也不尽相同.还需要多使用体会.
输出结果:手动Copy > cglibCopy > springBeanUtils > apachePropertyUtils > apacheBeanUtils 可以理解为: 手工复制 > cglib > 反射 > Dozer。
类型Framework | 测试性能(10000调用次)time |
Pure get/set | 10ms |
Easy mapper | 46ms |
Cglib Beancopier | 11ms |
Spring BeanUtils | 94ms |
Apache BeanUtils | 249ms |
Apache PropertieyUtils | 130ms |
Dozer | 770ms |
对象属性拷贝工具类大全==>Bean的属性拷贝从此不用愁的更多相关文章
- [性能] Bean拷贝工具类性能比较
Bean拷贝工具类性能比较 引言 几年前做过一个项目,接入新的api接口.为了和api实现解耦,决定将api返回的实体类在本地也建一个.这样做有两个好处 可以在api变更字段的时候保持应用稳定性 可以 ...
- Dozer-对象属性映射工具类
Dozer-对象属性映射工具类 工具类代码: import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; impo ...
- spring工具类获取bean
import org.springframework.web.context.ContextLoader; import org.springframework.web.context.WebAppl ...
- 就因为加了Lombok的@Accessors(chain = true),bean拷贝工具类不干活了
前言 这次新建了一个工程,因为 Lombok 用得很习惯,但以前的话,一般只用了@Data,@AllArgsConstructor,@EqualsAndHashCode等常规注解:那这个Accesso ...
- java中map和对象互转工具类的实现示例
在项目开发中,经常碰到map转实体对象或者对象转map的场景,工作中,很多时候我们可能比较喜欢使用第三方jar包的API对他们进行转化,而且用起来也还算方便,比如像fastJson就可以轻松实现map ...
- springboot2.2.2企业级项目整合redis与redis 工具类大全
1.springboot2.2.2整合redis教程很多,为此编写了比较完整的redis工具类,符合企业级开发使用的工具类 2.springboot与redis maven相关的依赖 <depe ...
- Java Utils工具类大全(转)
源码和jar见:https://github.com/evil0ps/utils #Java Utils --- 封装了一些常用Java操作方法,便于重复开发利用. 另外希望身为Java牛牛的你们一起 ...
- Java Utils工具类大全
源码和jar见:https://github.com/evil0ps/utils #Java Utils --- 封装了一些常用Java操作方法,便于重复开发利用. 另外希望身为Java牛牛的你们一起 ...
- java读取属性配置文件工具类
import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * * 类: ProU ...
随机推荐
- C语言博客作业3--函数
C语言博客作业3--函数 1.本章学习总结 1.1思维导图 请以思维导图总结本周的学习内容,如下图所示: 1.2本章学习体会及代码量学习体会 1.2.1学习体会 描述本周学习感受,也可以在这里提出你不 ...
- python-web自动化-Js-日历操作
日历控件是web网站上经常会遇到的一个场景,有些输入框是可以直接输入日期的,有些不能:以12306网站为例,讲解如何解决日历控件为readonly属性的问题. 基本思路:先用js去掉readonly属 ...
- springCloud 服务注册启动报错<com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect>
报错:com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: ...
- 201772020113 李清华《面向对象程序设计(java)》第17周学习总结
1.实验目的与要求 (1) 掌握线程同步的概念及实现技术: (2) 线程综合编程练习 2.实验内容和步骤 实验1:测试程序并进行代码注释. 测试程序1: l 在Elipse环境下调试教材651页程序 ...
- C# ADO.NET中设置Like模糊查询的参数
ADO.NET进行参数化时会自动将参数值包含在单引号中,除了特殊需求,最好不要自己手动添加单引号.ADO.NET中识别参数标识是使用符号@,如果在SQL语句中将参数标识放在单引号中,单引号中的参数标识 ...
- python读取excel,返回dic列表
def get_xls_sheets_as_dic(pro_name, xls_name): dic_list = [] xls_path = os.path.join(BASE_PATH, &quo ...
- 接口--Comparable接口【哈夫曼树】
我们在字符串中见到过CompareTo方法,知道这个方法是用于比较字符串顺序的,根据字典顺序进行排序.Java中很多类也都有CompareTo方法,甚至于排序算法的底层组成也是依赖于比较的,而这个比较 ...
- OrderBy排序和IComparer的使用
https://www.cnblogs.com/May-day/p/7490334.html 一,OrderBy排序在MDSN中有两种使用方法,如下 1>第一种方法的使用,就是根据某个字段排序, ...
- SSM商城项目(十三)
1. 学习计划 1.订单系统 2.提交订单 3.MyCAT 2. 订单系统 2.1. 功能分析 1.在购物车页面点击“去结算”按钮跳转到订单确认页面. a) 展示商品列表 b) ...
- @Transactional 事务说明
这里面有几点需要大家留意:A. 一个功能是否要事务,必须纳入设计.编码考虑.不能仅仅完成了基本功能就ok.B. 如果加了事务,必须做好开发环境测试(测试环境也尽量触发异常.测试回滚),确保事务生效.C ...