前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java 代码实例 14】BeanUtils用法详解,附源码分析

【Java 代码实例 14】BeanUtils用法详解,附源码分析

作者头像
全栈程序员站长
发布2022-10-01 14:00:03
8980
发布2022-10-01 14:00:03
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

在这里插入图片描述
在这里插入图片描述

目录

一、org.apache.commons.beanutils.BeanUtils简介

BeanUtilsApache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。​ 简化反射封装参数的步骤,给对象封装参数,好处是BeanUtils给对象封装参数的时候会进行类型自动转换。

二、使用的前置条件

  1. 类//必须使用public修饰
  2. 提供无参数的构造器
  3. 提供gettersetter方法访问属性

三、添加pom

代码语言:javascript
复制
<dependency>
     <groupId>commons-beanutils</groupId>
     <artifactId>commons-beanutils</artifactId>
     <version>1.9.4</version>
</dependency>

四、org.apache.commons.beanutils.BeanUtils代码实例

在这里插入图片描述
在这里插入图片描述

1、为属性赋值

代码语言:javascript
复制
private static void setUserProperty() throws Exception { 

Worker worker = new Worker();
BeanUtils.setProperty(worker, "id", "1");
BeanUtils.setProperty(worker, "name", "哪吒");
BeanUtils.setProperty(worker, "age", "28");
System.out.println("id:"+ BeanUtils.getProperty(worker, "id"));
System.out.println(worker);
}

2、拷贝对象,为对象赋值

代码语言:javascript
复制
private static void cloneBean() throws Exception { 

Worker worker1 = new Worker(3,"哪吒",18);
// 拷贝对象
Object object = BeanUtils.cloneBean(worker1);
Worker worker2 = (Worker)object;
System.out.println(worker2);//Worker{id=3, name='哪吒', age=18}
System.out.println("worker1==worker2 : "+(worker1==worker2));//false
// 拷贝对象属性
Worker worker3 = new Worker();
BeanUtils.copyProperties(worker3,worker1);
System.out.println(worker3);//Worker{id=3, name='哪吒', age=18}
System.out.println("worker1==worker3 : "+(worker1==worker3));//false
// 为属性赋值
Worker worker4 = new Worker();
BeanUtils.copyProperty(worker4,"age",30);
System.out.println(worker4);//Worker{id=0, name='null', age=30}
}

3、map转bean

代码语言:javascript
复制
private static void mapToBean() throws Exception { 

Map<String, Object> map = new HashMap<String, Object>();
map.put("id",2);
map.put("name","哪吒");
map.put("age",29);
Worker user = new Worker();
BeanUtils.populate(user,map);
System.out.println(user);
}

4、bean转map

代码语言:javascript
复制
private static void beanToMap() throws Exception { 

Worker worker = new Worker(4,"哪吒编程",18);
Map<String, String> map = BeanUtils.describe(worker);
System.out.println(map);//{name=哪吒, id=4, age=18}
// 为什么返回值是一个数组呢?
String[] names = BeanUtils.getArrayProperty(worker, "name");
System.out.println(names[0]);
}

五、Apache的BeanUtils与Spring的BeanUtils

在这里插入图片描述
在这里插入图片描述

默认情况下,使用org.apache.commons.beanutils.BeanUtils对复杂对象是进行的浅拷贝,但是由于Apache下的BeanUtils对象拷贝性能太差,不建议使用,这在阿里巴巴Java开发规约插件上也明确指出:

Ali-Check | 避免用Apache Beanutils进行属性的copy。

到这里你可能会疑惑,为什么会出现拷贝性能差的情况呢?

因为在对对象进行拷贝的时候添加很多的校验,比如像类型转换,甚至还校验了对象所属类的访问权限,可以说校验是相当的复杂,这也就是造成性能差的根本原因,我们看下它的具体代码实现:

代码语言:javascript
复制
public void copyProperties(final Object dest, final Object orig)
throws IllegalAccessException, InvocationTargetException { 

// Validate existence of the specified beans
if (dest == null) { 

throw new IllegalArgumentException
("No destination bean specified");
}
if (orig == null) { 

throw new IllegalArgumentException("No origin bean specified");
}
if (log.isDebugEnabled()) { 

log.debug("BeanUtils.copyProperties(" + dest + ", " +
orig + ")");
}
// Copy the properties, converting as necessary
if (orig instanceof DynaBean) { 

final DynaProperty[] origDescriptors =
((DynaBean) orig).getDynaClass().getDynaProperties();
for (DynaProperty origDescriptor : origDescriptors) { 

final String name = origDescriptor.getName();
// Need to check isReadable() for WrapDynaBean
// (see Jira issue# BEANUTILS-61)
if (getPropertyUtils().isReadable(orig, name) &&
getPropertyUtils().isWriteable(dest, name)) { 

final Object value = ((DynaBean) orig).get(name);
copyProperty(dest, name, value);
}
}
} else if (orig instanceof Map) { 

@SuppressWarnings("unchecked")
final
// Map properties are always of type <String, Object>
Map<String, Object> propMap = (Map<String, Object>) orig;
for (final Map.Entry<String, Object> entry : propMap.entrySet()) { 

final String name = entry.getKey();
if (getPropertyUtils().isWriteable(dest, name)) { 

copyProperty(dest, name, entry.getValue());
}
}
} else /* if (orig is a standard JavaBean) */ { 

final PropertyDescriptor[] origDescriptors =
getPropertyUtils().getPropertyDescriptors(orig);
for (PropertyDescriptor origDescriptor : origDescriptors) { 

final String name = origDescriptor.getName();
if ("class".equals(name)) { 

continue; // No point in trying to set an object's class
}
if (getPropertyUtils().isReadable(orig, name) &&
getPropertyUtils().isWriteable(dest, name)) { 

try { 

final Object value =
getPropertyUtils().getSimpleProperty(orig, name);
copyProperty(dest, name, value);
} catch (final NoSuchMethodException e) { 

// Should not happen
}
}
}
}
}

org.springframework.beans.BeanUtils是使用 copyProperties方法进行拷贝,不过实现的方式相对于前者要来得简单得多了,可以说是非常的简单,就是根据两个对象属性的名字进行匹配,做简单的 get/set,仅检查属性的可访问性。具体实现如下:

代码语言:javascript
复制
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,
@Nullable 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 && (ignoreList == 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);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { 

writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
catch (Throwable ex) { 

throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}

从上面的实现源码可以看到:成员变量赋值是基于目标对象的成员列表,并且会跳过ignore以及在源对象中不存在的属性,所以这个方法是安全的,不会因为两个对象之间的结构差异导致错误,但是必须保证同名的两个成员变量类型相同。 以上简要的分析两种BeanUtils的具体实现以及性能相关的分析,得出结论:Apache下的BeanUtils由于各种繁琐的校验以及可访问性的校验等等,导致性能较差,故实际开发中不建议使用,可以使用 Spring的BeanUtils

六、org.springframework.beans.BeanUtils代码实例

1、实例化

代码语言:javascript
复制
package com.guor.beanutil.spring;
import com.guor.beanutil.Worker;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
public class SpringBeanUtilsTest { 

@Test
public void testInstantiate() throws Exception{ 

//通过无参数构造函数实例化
Object obj = BeanUtils.instantiateClass(Worker.class);
if(obj instanceof Worker) { 

System.out.println(((Worker) obj).getNezha());//哪吒
}
//通过有参数构造函数实例化
Object obj2 = BeanUtils.instantiateClass(Worker.class.getDeclaredConstructor(String.class), "哪吒编程");
if(obj2 instanceof Worker) { 

System.out.println(((Worker) obj2).getNezha());//哪吒编程
}
}
}
在这里插入图片描述
在这里插入图片描述

2、查找方法

(1)无参调用

代码语言:javascript
复制
@Test
public void testFindDeclaredMethod() throws Exception { 

Worker worker = new Worker();
worker.setId(8);
worker.setName("哪吒");
Method method = BeanUtils.findDeclaredMethod(Worker.class, "getName");
Object name = method.invoke(worker);
System.out.println(name);//哪吒
}

(2)有参调用

代码语言:javascript
复制
@Test
public void testPropertyDescriptor2() throws Exception { 

Worker worker = new Worker();
worker.setId(10);
worker.setName("哪吒");
Method method = BeanUtils.findMethod(Worker.class, "sayMsg",String.class,String.class);
method.invoke(worker,"哪吒","我很帅");//哪吒 say :我很帅
}

(3)如果找不到方法

在这里插入图片描述
在这里插入图片描述

3、查找属性

代码语言:javascript
复制
@Test
public void testPropertyDescriptor() throws Exception { 

Worker worker = new Worker();
worker.setId(10);
worker.setName("哪吒");
//获取属性
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(Worker.class, "name");
//获取属性的get方法
Method getMethod = pd.getReadMethod();
Object name = getMethod.invoke(worker);
System.out.println(name);//哪吒
//获取属性的get方法
Method setMethod = pd.getWriteMethod();
setMethod.invoke(worker, "哪吒编程");
System.out.println(worker.getName());//哪吒编程
}

七、更多的Java代码实例

【Java 代码实例 4】javacompiler编译多java文件 【Java 代码实例 6】FileUtils、StringUtil、CollectionUtils、ArrayUtils(附代码示例) 【Java 代码实例 7】jsoup解析html 【Java 代码实例 8】qrcode生成二维码 【Java 代码实例 9】Java通过Process执行C# exe程序 【Java 代码实例 13】Java操作pdf的工具类itext

如果您有什么Java方面的需求,可以写在评论区,哪吒会一一进行回复,力争做到《你想知道的Java知识,哪吒都有》,加油!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/194871.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月11日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 一、org.apache.commons.beanutils.BeanUtils简介
  • 二、使用的前置条件
  • 三、添加pom
  • 四、org.apache.commons.beanutils.BeanUtils代码实例
    • 1、为属性赋值
      • 2、拷贝对象,为对象赋值
        • 3、map转bean
          • 4、bean转map
          • 五、Apache的BeanUtils与Spring的BeanUtils
          • 六、org.springframework.beans.BeanUtils代码实例
            • 1、实例化
              • 2、查找方法
                • 3、查找属性
                • 七、更多的Java代码实例
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档