有關(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)文章
Java動(dòng)態(tài)設(shè)置注解值及原理詳解
這篇文章主要介紹了Java動(dòng)態(tài)設(shè)置注解值及原理詳解,AnnotationInvocationHandler是注解的代理hander,通過反射獲取類的注解時(shí)會(huì)通過AnnotationInvocationHandler創(chuàng)建代理對(duì)象并將數(shù)據(jù)存儲(chǔ)到memberValues里,需要的朋友可以參考下2023-11-11Linux?Ubuntu系統(tǒng)下配置JDK環(huán)境、MySQL環(huán)境全過程
眾所周知Ubuntu是一種基于Linux的操作系統(tǒng),它提供了一個(gè)穩(wěn)定、安全和易于使用的環(huán)境,下面這篇文章主要給大家介紹了關(guān)于Linux?Ubuntu系統(tǒng)下配置JDK環(huán)境、MySQL環(huán)境的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07Spring?component-scan?XML配置與@ComponentScan注解配置
這篇文章主要介紹了Spring?component-scan?XML配置與@ComponentScan注解配置,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Spring如何根據(jù)條件創(chuàng)建bean,@Conditional注解使用方式
這篇文章主要介紹了Spring如何根據(jù)條件創(chuàng)建bean,@Conditional注解使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Java 實(shí)戰(zhàn)項(xiàng)目錘煉之樸素風(fēng)格個(gè)人博客系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java+vue+Springboot+ssm+mysql+maven+redis實(shí)現(xiàn)一個(gè)樸素風(fēng)格的個(gè)人博客系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11手把手帶你了解Java-Stream流方法學(xué)習(xí)及總結(jié)
這篇文章主要介紹了通過實(shí)例了解JavaStream流的方法學(xué)習(xí)和總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-08-08java中ArrayList和LinkedList的區(qū)別詳解
這篇文章主要介紹了java中ArrayList和LinkedList的區(qū)別詳解,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01