有關(guān)Java中的BeanInfo介紹
1、JavaBean介紹
維基百科JavaBean的定義:JavaBeans是Java中一種特殊的類,可以將多個(gè)對(duì)象封裝到一個(gè)對(duì)象(bean)中。特點(diǎn)是可序列化,提供無參構(gòu)造器,提供getter方法和setter方法訪問對(duì)象的屬性。名稱中的“Bean”是用于Java的可重用軟件組件的慣用叫法。要成為JavaBean類,則必需遵循關(guān)于命名、構(gòu)造器、方法的特定規(guī)范。有了這些規(guī)范,才能有可以使用、復(fù)用、替代和連接JavaBeans的工具。規(guī)范如下:
- 有一個(gè)public的無參數(shù)構(gòu)造器。
- 屬性可以通過
get、set、is(可以替代get,用在布爾型屬性上)方法或遵循特定命名規(guī)范的其他方法訪問。 - 可序列化。
以下為一個(gè)合法的JavaBean的定義:
public class PersonBean implements java.io.Serializable {
/**
* name 屬性(注意大小寫)
*/
private String name = null;
private boolean deceased = false;
/** 無參構(gòu)造器(沒有參數(shù)) */
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;
}
}

2、JavaBean的自省
用一個(gè)簡(jiǎn)單的SpringMVC用戶登錄的場(chǎng)景來描述一下JavaBean的自省,用戶登錄時(shí)候,前端表單傳遞的參數(shù)通常是一個(gè)如下Json字符串:
{
"username":"xxx",
"password":"xxxx"
}
后端接受表單的地方,通??梢允褂靡粋€(gè)JavaBean用RequestBody的形式接收參數(shù):
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中的對(duì)應(yīng)屬性之上呢?可以看到LoginRequest中的字段都是private類型,無法直接設(shè)置字段值(反射雖然可以設(shè)置,但是并不合適),只能通過Setter方法進(jìn)行設(shè)置,但是程序怎么知道JavaBean有哪些Setter方法呢?此處就用到了JavaBean的內(nèi)省機(jī)制。

3、JavaBean內(nèi)省工具Introspector
Java bean的工具包中提供了java內(nèi)省工具Introspector,該工具可以通過以下方法獲取Java bean 的內(nèi)省結(jié)果BeanInfo(后文詳細(xì)介紹),獲取BeanInfo的流程如下圖所示
// 在Object類時(shí)候停止檢索,可以選擇在任意一個(gè)父類停止 BeanInfo beanInfo = Introspector.getBeanInfo(JavaBeanDemo.class,Object.class);

4、JavaBean內(nèi)省結(jié)果BeanInfo
通過java的內(nèi)省工具Introspector的getBeanInfo方法,我們可以獲取一個(gè)JavaBean的內(nèi)省BeanInfo,獲取到的BeanInfo包含以下屬性:
- Bean的類相關(guān)信息
- Bean的事件信息
- Bean的屬性信息
- Bean的方法信息
- 額外屬性信息
- Component的圖標(biāo)

5、內(nèi)省結(jié)果BeanInfo的類型
BeanInfo只是一個(gè)內(nèi)省結(jié)果的接口,Java中對(duì)該接口的實(shí)現(xiàn)有以下三種:
- ApplicationBeanInfo:
Apple desktop相關(guān)的JavaBean內(nèi)省結(jié)果 - ComponentBeanInfo:
Java Awt組件的內(nèi)省結(jié)果,如按鈕等 - GenericBeanInfo:通用的內(nèi)省結(jié)果,JEE開發(fā)中的內(nèi)省結(jié)果都為該類型
此外,Spring自定義了一個(gè)內(nèi)省結(jié)果類型,叫ExtendedBeanInfo,主要用于識(shí)別返回值不為空的Setter方法。

6、Spring的BeanUtils.copyProperties
BeanUtils.copyProperties用戶在兩個(gè)對(duì)象之間進(jìn)行屬性的復(fù)制,底層基于JavaBean的內(nèi)省機(jī)制,通過內(nèi)省得到拷貝源對(duì)象和目的對(duì)象屬性的讀方法和寫方法,然后調(diào)用對(duì)應(yīng)的方法進(jìn)行屬性的復(fù)制。以下為BeanUtils.copyProperties的流程

BeanUtils對(duì)JavaBean內(nèi)省的一些機(jī)制進(jìn)行優(yōu)化,到這里,大家有沒有發(fā)現(xiàn)Java內(nèi)省的一些缺點(diǎn)呢?
7、BeanUtils并發(fā)問題優(yōu)化
Java內(nèi)省的結(jié)果會(huì)緩存在ThreadGroupContext中,并且通過synchonrized關(guān)鍵字對(duì)緩存加鎖(下圖中的紅框部分),導(dǎo)致同一個(gè)線程組中的線程無法并行內(nèi)省。

Spring的BeanUtils在Java內(nèi)省之上又添加了一層緩存,這層緩存使用ConcurrentHashMap實(shí)現(xiàn),從而提高了內(nèi)省的效率。
8、BeanUtils Setter屬性識(shí)別優(yōu)化
在Java默認(rèn)的內(nèi)省過程中,setter方法的返回值必須是null,如果不是null的話,無法識(shí)別為有效的JavaBean屬性(下圖中的紅色部分),Spring 自定義了一個(gè)BeanInfo ExtendedBeanInfo解決了這個(gè)問題。

回到最初提到的spring.beaninfo.ignore,這個(gè)配置用來忽略所有自定義的BeanInfo類的搜索.
9、BeanUtils 性能測(cè)試

可以看出:BeanUtils花費(fèi)的時(shí)間約為直接復(fù)制的50倍以上。
public class BeanUtilsPerformanceTest {
public static void main(String[] args){
// 預(yù)熱虛擬機(jī)
loopBeanUtils(100000);
loopCopyByHand(100000);
// 復(fù)制1萬次的情況
System.out.println("\nloop 10000 times:");
loopBeanUtils(10000);
loopCopyByHand(10000);
// 復(fù)制1百萬次的情況
System.out.println("\nloop 1000000 times:");
loopBeanUtils(1000000);
loopCopyByHand(1000000);
// 復(fù)制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();
}
}
到此這篇關(guān)于有關(guān)Java中的BeanInfo介紹的文章就介紹到這了,更多相關(guān)Java中的BeanInfo內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot配置Jackson返回統(tǒng)一默認(rèn)值的實(shí)現(xiàn)示例
在項(xiàng)目開發(fā)中,我們返回的數(shù)據(jù)或者對(duì)象沒有的時(shí)候一般直接返回的null,那么如何返回統(tǒng)一默認(rèn)值,感興趣的可以了解一下2021-07-07
Java實(shí)現(xiàn)系統(tǒng)限流的示例代碼
限流是保障系統(tǒng)高可用的方式之一,也是大廠高頻面試題,它在微服務(wù)系統(tǒng)中,緩存、限流、熔斷是保證系統(tǒng)高可用的三板斧,所以本文我們就來聊聊如何實(shí)現(xiàn)系統(tǒng)限流吧2023-09-09
Java實(shí)現(xiàn)單機(jī)版五子棋游戲的示例代碼
五子棋是世界智力運(yùn)動(dòng)會(huì)競(jìng)技項(xiàng)目之一,是一種兩人對(duì)弈的純策略型棋類游戲,是世界智力運(yùn)動(dòng)會(huì)競(jìng)技項(xiàng)目之一。本文將用java語言實(shí)現(xiàn)單機(jī)版五子棋游戲,感興趣的可以了解一下2022-09-09
Java Properties簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Java中有個(gè)比較重要的類Properties(Java.util.Properties),主要用于讀取Java的配置文件,各種語言都有自己所支持的配置文件,配置文件中很多變量是經(jīng)常改變的,這樣做也是為了方便用戶,讓用戶能夠脫離程序本身去修改相關(guān)的變量設(shè)置2017-05-05
Java如何在沙箱環(huán)境中測(cè)試支付寶支付接口
這篇文章主要介紹了Java如何在沙箱環(huán)境中測(cè)試支付寶支付接口,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Spring Boot實(shí)現(xiàn)郵件發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了Spring Boot實(shí)現(xiàn)郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

