Java的BeanInfo在工作中并不怎么用到,我也是在学习spring源码的时候,发现SpringBoot启动时候会设置一个属叫"spring.beaninfo.ignore",网上只能搜索到这个配置的意思是是否跳过java BeanInfo的搜索,没找到其他信息,但是BeanInfo又是什么呢?

JavaBean介绍

维基百科JavaBean的定义:JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。要成为JavaBean类,则必需遵循关于命名、构造器、方法的特定规范。有了这些规范,才能有可以使用、复用、替代和连接JavaBeans的工具。规范如下:

  • 有一个public的无参数构造器。
  • 属性可以通过get、set、is(可以替代get,用在布尔型属性上)方法或遵循特定命名规范的其他方法访问。
  • 可序列化。

以下为一个合法的JavaBean的定义:

public class PersonBean implements java.io.Serializable {

    /**
* name 属性(注意大小寫)
*/
private String name = null; private boolean deceased = false; /** 无参构造器(没有参数) */
public PersonBean() {
} /**
* name 属性的Getter方法
*/
public String getName() {
return name;
} /**
* name 属性的Setter方法
* @param value
*/
public void setName(final String value) {
name = value;
} /**
* deceased 属性的Getter方法
* 布尔型属性的Getter方法的不同形式(这里使用了is而非get)
*/
public boolean isDeceased() {
return deceased;
} /**
* deceased 属性的Setter方法
* @param value
*/
public void setDeceased(final boolean value) {
deceased = value;
}
}

JavaBean的自省

用一个简单的SpringMVC用户登录的场景来描述一下JavaBean的自省,用户登录时候,前端表单传递的参数通常是一个如下Json字符串:

{
"username":"xxx",
"password":"xxxx"
}

后端接受表单的地方,通常可以使用一个JavaBean用RequestBody的形式接收参数:

public void login(@RequestBody LoginRequest request){
// Do login
}

其中,LoginRequest类似于如下的格式:

public class LoginRequest {
public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} private String username;
private String password;
}

那么前端的Json如何映射到后端LoginRequest中的对应属性之上呢?可以看到LoginRequest中的字段都是private类型,无法直接设置字段值(反射虽然可以设置,但是并不合适),只能通过Setter方法进行设置,但是程序怎么知道JavaBean有哪些Setter方法呢?此处就用到了JavaBean的内省机制。

JavaBean内省工具Introspector

Java bean的工具包中提供了java内省工具Introspector,该工具可以通过以下方法获取Java bean 的内省结果BeanInfo(后文详细介绍),获取BeanInfo的流程如下图所示

// 在Object类时候停止检索,可以选择在任意一个父类停止
BeanInfo beanInfo = Introspector.getBeanInfo(JavaBeanDemo.class,Object.class);

JavaBean内省结果BeanInfo

通过java的内省工具Introspector的getBeanInfo方法,我们可以获取一个JavaBean的内省BeanInfo,获取到的BeanInfo包含以下属性:

  • Bean的类相关信息
  • Bean的事件信息
  • Bean的属性信息
  • Bean的方法信息
  • 额外属性信息
  • Component的图标

内省结果BeanInfo的类型

BeanInfo只是一个内省结果的接口,Java中对该接口的实现有以下三种:

  1. ApplicationBeanInfo:Apple desktop相关的JavaBean内省结果
  2. ComponentBeanInfo:Java Awt组件的内省结果,如按钮等
  3. GenericBeanInfo:通用的内省结果,JEE开发中的内省结果都为该类型

此外,Spring自定义了一个内省结果类型,叫ExtendedBeanInfo,主要用于识别返回值不为空的Setter方法。

Spring的BeanUtils.copyProperties

BeanUtils.copyProperties用户在两个对象之间进行属性的复制,底层基于JavaBean的内省机制,通过内省得到拷贝源对象和目的对象属性的读方法和写方法,然后调用对应的方法进行属性的复制。以下为BeanUtils.copyProperties的流程

BeanUtils对JavaBean内省的一些机制进行优化,到这里,大家有没有发现Java内省的一些缺点呢?

BeanUtils并发问题优化

Java内省的结果会缓存在ThreadGroupContext中,并且通过synchonrized关键字对缓存加锁(下图中的红框部分),导致同一个线程组中的线程无法并行内省。

Spring的BeanUtils在Java内省之上又添加了一层缓存,这层缓存使用ConcurrentHashMap实现,从而提高了内省的效率。

BeanUtils Setter属性识别优化

在Java默认的内省过程中,setter方法的返回值必须是null,如果不是null的话,无法识别为有效的JavaBean属性(下图中的红色部分),Spring 自定义了一个BeanInfo ExtendedBeanInfo解决了这个问题。

spring.beaninfo.ignore

回到最初提到的spring.beaninfo.ignore,这个配置用来忽略所有自定义的BeanInfo类的搜索.

BeanUtils 性能测试

复制方法 1万次复制耗时 1百万次复制耗时 1亿次复制耗时
ModelMapper复制 262mills 3875mills 283177mills
BeanUtils复制 3mills 369mills 20347mills
直接复制 约等于0mills 5mills 438mills

可以看出:BeanUtils花费的时间约为直接复制的50倍以上。

public class BeanUtilsPerformanceTest {

    public static void main(String[] args){
// 预热虚拟机
loopBeanUtils(100000);
loopCopyByHand(100000); // 复制1万次的情况
System.out.println("\nloop 10000 times:");
loopBeanUtils(10000);
loopCopyByHand(10000); // 复制1百万次的情况
System.out.println("\nloop 1000000 times:");
loopBeanUtils(1000000);
loopCopyByHand(1000000); // 复制1亿次的情况
System.out.println("\nloop 100000000 times:");
loopBeanUtils(100000000);
loopCopyByHand(100000000);
} private static void loopBeanUtils(int loopTimes){
TestBeanDemo source = new TestBeanDemo();
TestBeanDemo target = new TestBeanDemo();
long start = System.currentTimeMillis();
for (int i=0;i<loopTimes;i++){
BeanUtils.copyProperties(source,target);
}
System.out.println("BeanUtils cost times:"+String.valueOf(System.currentTimeMillis()-start));
} private static void loopCopyByHand(int loopTimes){
TestBeanDemo source = new TestBeanDemo();
TestBeanDemo target = new TestBeanDemo();
long start = System.currentTimeMillis();
for (int i=0;i<loopTimes;i++){
target.setField1(source.getField1());
target.setField2(source.getField2());
target.setField3(source.getField3());
target.setField4(source.getField4());
target.setField5(source.getField5());
}
System.out.println("Copy field one by one times:"+String.valueOf(System.currentTimeMillis()-start));
} @Data
private static class TestBeanDemo{
private String field1 = UUID.randomUUID().toString();
private String field2 = UUID.randomUUID().toString();
private String field3 = UUID.randomUUID().toString();
private String field4 = UUID.randomUUID().toString();
private String field5 = UUID.randomUUID().toString(); }
}

我是御狐神,欢迎大家关注我的微信公众号:wzm2zsd

本文最先发布至微信公众号,版权所有,禁止转载!

JavaBean内省与BeanInfo的更多相关文章

  1. jsp 以及javabean内省技术

    l JSP l JavaBean及内省 l EL表达式 1.1 上次课内容回顾 会话技术: Cookie:客户端技术.将数据保存在客户端浏览器上.Cookie是有大小和个数的限制. Session:服 ...

  2. 黑马程序员:Java基础总结----JavaBean 内省

    黑马程序员:Java基础总结 JavaBean 内省   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! JavaBean  内省 软件包 java.beans 包含与开 ...

  3. Java高新技术 JavaBean内省

     Java高新技术  JavaBean内省 知识概要:                 (1)了解JavaBean内省                 (2)JavaBean的简单内省操作     ...

  4. Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用

    Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/101174 ...

  5. JavaBean 内省API BeanUtils工具 泛型 xml xml约束

    1 什么是JavaBean?有何特征? 1)符合特定规则的类    2)JavaBean分二类:     a)侠义的JavaBean         .私有的字段(Field)         .对私 ...

  6. javabean内省

    何为JavaBean? JavaBean 是一种JAVA语言写成的可重用组件.为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器.JavaBean 通过提供符合一致性设计模式的公共 ...

  7. JavaEE JavaBean 反射、内省、BeanUtils

    JavaEE JavaBean 反射.内省.BeanUtils @author ixenos JavaBean是什么 一种规范,表达实体和信息的规范,便于封装重用. 1.所有属性为private2.提 ...

  8. 内省详解(Introspector/BeanInfo/MethodDescriptor/PropertyDescriptor)

    内省(Introspector)概念 ​ 内省Introspector 是Java提供的操作 JavaBean 的 API,用来访问某个属性的 getter/setter 方法.对于一个标准的 Jav ...

  9. 内省机制(操作javaBean的信息)

    内省机制(操作javaBean的信息) ----是不是联想到了反射机制了哈,这两者有什么区别呢? 1.内省机制和反射机制的联系 ■ 其实内省机制也是通过反射来实现的,而反射是对一切类都适合去动态获取类 ...

随机推荐

  1. C/C++编程笔记:浪漫流星雨表白装b程序

    作为一个未来可能会成为一个专业程序员的小伙们,不知道你们现在学到哪里了,学了点东西之后有没有想在你女朋友面前装个大大的b呢,今天小编就给你一个机会来研究一下下边的代码吧,保证大写的N,当然大佬是排除在 ...

  2. 绘制PCB电路原理图的8种方法

    1.选择集成电路,变压器,晶体管等组件,这些组件体积庞大,有许多引脚并在电路中起主要作用,然后从选定的参考引脚中抽取,以减少错误. 2.如果PCB上标有元件编号(如VD870,R330,C466等), ...

  3. 手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序

    上一篇:手把手教你学Dapr - 2. 必须知道的概念 注意: 文章中提到的命令行工具即是Windows Terminal/PowerShell/cmd其中的一个,推荐使用Windows Termin ...

  4. hdu 2199 Can you solve this equation?(二分法求多项式解)

    题意 给Y值,找到多项式 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y 在0到100之间的解. 思路 从0到100,多项式是单调的,故用二分法求解. 代码 double c ...

  5. linux 内核源代码情景分析——linux 内核源代码中的C语言代码

    linux 内核的主体是以GNU的C语言编写的,GNU为此提供了编译工具gcc.GNU对C语言本身作了不少扩充. 1) gcc 从 C++ 语言中吸收了"inline"和" ...

  6. Zabbix 4.4 离线安装 使用mariadb的踩坑,无法停止服务

    先分享一个网站,之前就没注意过有这个网站,不知道是啥时候开放的.里面分享了N多zabbix的模板. https://share.zabbix.com/ 报错如下 Unsupported charset ...

  7. 文件挂载swap

    根目录使用率超过79%,根目录总共45G,/home目录下有文件6G的swap,在新加的300G分区/OracleDB中建立4个G的swap替代/home下在swap文件 1.创建4个G的空文件 #  ...

  8. 小入门 Django(做个疫情数据报告)

    Django 是 Python web框架,发音 [ˈdʒæŋɡo] ,翻译成中文叫"姜狗". 为什么要学框架?其实我们自己完全可以用 Python 代码从0到1写一个web网站, ...

  9. linux删除文件未释放

    https://access.redhat.com/solutions/2316 $ /usr/sbin/lsof | grep deleted ora 25575 data 33u REG 65,6 ...

  10. 我罗斯方块第二次作业(Player类)

    我罗斯方块第二次作业 我的任务 完成player类的编写 player类的测试 我的计划 类的设计: Player类作为一个玩家类,需要处理和玩家有关的所有信息,以及维护玩家的游戏页面map.关于玩家 ...