• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于java:Java基础之BeanInfo

java 搞代码 4年前 (2022-01-27) 39次浏览 已收录 0个评论
文章目录[隐藏]

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的定义:

<code class="java">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字符串:

<code class="json">{
    "username":"xxx",
    "password":"xxxx"
}

后端承受表单的中央,通常能够应用一个JavaBean用RequestBody的模式接管参数:

<code class="java">public void login(@RequestBody LoginRequest request){
     // Do login
}

其中,LoginRequest相似于如下的格局:

<code class="java">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的流程如下图所示

<code class="java">// 在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倍以上。

<code class="java">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();

    }
}

我是御狐神,欢送大家关注我的微信公众号
<br/>

版权所有,禁止转载!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于java:Java基础之BeanInfo

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址