溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java內(nèi)省Introspector相關(guān)類(lèi)有哪些

發(fā)布時(shí)間:2021-11-30 14:48:56 來(lái)源:億速云 閱讀:143 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“Java內(nèi)省Introspector相關(guān)類(lèi)有哪些”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Java內(nèi)省Introspector相關(guān)類(lèi)有哪些”吧!

JavaBean是什么

JavaBean是一種特殊(其實(shí)說(shuō)普通也可以,也不是十分特殊)的類(lèi),主要用于傳遞數(shù)據(jù)信息,這種類(lèi)中的方法主要用于訪問(wèn)私有的字段,且方法名符合某種命名規(guī)則(字段都是私有,每個(gè)字段具備SetterGetter方法,方法和字段命名滿足首字母小寫(xiě)駝峰命名規(guī)則)。如果在兩個(gè)模塊之間傳遞信息,可以將信息封裝進(jìn)JavaBean中,這種對(duì)象稱(chēng)為值對(duì)象(Value Object)或者VO。這些信息儲(chǔ)存在類(lèi)的私有變量中,通過(guò)SetterGetter方法獲得。JavaBean的信息在Introspector里對(duì)應(yīng)的概念是BeanInfo,它包含了JavaBean所有的Descriptor(描述符),主要有PropertyDescriptor,MethodDescriptorMethodDescriptor里面包含ParameterDescriptor)、BeanDescriptorEventSetDescriptor。 

屬性Field和屬性描述PropertiesDescriptor的區(qū)別

如果是嚴(yán)格的JavaBean(Field名稱(chēng)不重復(fù),并且Field具備SetterGetter方法),它的PropertyDescriptor會(huì)通過(guò)解析SetterGetter方法,合并解析結(jié)果,最終得到對(duì)應(yīng)的PropertyDescriptor實(shí)例。所以PropertyDescriptor包含了屬性名稱(chēng)和屬性的SetterGetter方法(如果存在的話)。 

內(nèi)省Introspector和反射Reflection的區(qū)別

  • Reflection:反射就是運(yùn)行時(shí)獲取一個(gè)類(lèi)的所有信息,可以獲取到類(lèi)的所有定義的信息(包括成員變量,成員方法,構(gòu)造器等)可以操縱類(lèi)的字段、方法、構(gòu)造器等部分??梢韵胂鬄殓R面反射或者照鏡子,這樣的操作是帶有客觀色彩的,也就是反射獲取到的類(lèi)信息是必定正確的。
  • Introspector:內(nèi)省基于反射實(shí)現(xiàn),主要用于操作     JavaBean,基于     JavaBean的規(guī)范進(jìn)行     Bean信息描述符的解析,依據(jù)于類(lèi)的     Setter和     Getter方法,可以獲取到類(lèi)的描述符??梢韵胂鬄?quot;自我反省",這樣的操作帶有主觀的色彩,不一定是正確的(如果一個(gè)類(lèi)中的屬性沒(méi)有     Setter和     Getter方法,無(wú)法使用     Introspector)。 

常用的Introspector相關(guān)類(lèi)

主要介紹一下幾個(gè)核心類(lèi)所提供的方法。 

Introspector

Introspector類(lèi)似于BeanInfo的靜態(tài)工廠類(lèi),主要是提供靜態(tài)方法通過(guò)Class實(shí)例獲取到BeanInfo,得到BeanInfo之后,就能夠獲取到其他描述符。主要方法:

  • public static BeanInfo getBeanInfo(Class<?> beanClass):通過(guò)     Class實(shí)例獲取到     BeanInfo實(shí)例。 

BeanInfo

BeanInfo是一個(gè)接口,具體實(shí)現(xiàn)是GenericBeanInfo,通過(guò)這個(gè)接口可以獲取一個(gè)類(lèi)的各種類(lèi)型的描述符。主要方法:

  • BeanDescriptor getBeanDescriptor():獲取     JavaBean描述符。
  • EventSetDescriptor[] getEventSetDescriptors():獲取     JavaBean的所有的     EventSetDescriptor
  • PropertyDescriptor[] getPropertyDescriptors():獲取     JavaBean的所有的     PropertyDescriptor。
  • MethodDescriptor[] getMethodDescriptors():獲取     JavaBean的所有的     MethodDescriptor

這里要注意一點(diǎn),通過(guò)BeanInfo#getPropertyDescriptors()獲取到的PropertyDescriptor數(shù)組中,除了Bean屬性的之外,「還會(huì)帶有一個(gè)屬性名為classPropertyDescriptor實(shí)例」,它的來(lái)源是ClassgetClass方法,如果不需要這個(gè)屬性那么最好判斷后過(guò)濾,這一點(diǎn)需要緊記,否則容易出現(xiàn)問(wèn)題。 

PropertyDescriptor

PropertyDescriptor類(lèi)表示JavaBean類(lèi)通過(guò)存儲(chǔ)器(SetterGetter)導(dǎo)出一個(gè)屬性,它應(yīng)該是內(nèi)省體系中最常見(jiàn)的類(lèi)。主要方法:

  • synchronized Class<?> getPropertyType():獲得屬性的     Class對(duì)象。
  • synchronized Method getReadMethod():獲得用于讀取屬性值(     Getter)的方法;
  • synchronized Method getWriteMethod():獲得用于寫(xiě)入屬性值(     Setter)的方法。
  • int hashCode():獲取對(duì)象的哈希值。
  • synchronized void setReadMethod(Method readMethod):設(shè)置用于讀取屬性值(     Getter)的方法。
  • synchronized void setWriteMethod(Method writeMethod):設(shè)置用于寫(xiě)入屬性值(     Setter)的方法。

舉個(gè)例子:

public class Main {

    public static void main(String[] args) throws Exception {
        BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            if (!"class".equals(propertyDescriptor.getName())) {
                System.out.println(propertyDescriptor.getName());
                System.out.println(propertyDescriptor.getWriteMethod().getName());
                System.out.println(propertyDescriptor.getReadMethod().getName());
                System.out.println("=======================");
            }
        }
    }

    public static class Person {

        private Long id;
        private String name;
        private Integer age;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }
    }
}
 

輸出結(jié)果:

age
setAge
getAge
=======================
id
setId
getId
=======================
name
setName
getName
=======================
   

不正當(dāng)使用Introspector會(huì)導(dǎo)致內(nèi)存溢出

如果框架或者程序用到了JavaBeans Introspector,那么就相當(dāng)于「啟用了一個(gè)系統(tǒng)級(jí)別的緩存」,這個(gè)緩存會(huì)存放一些曾加載并分析過(guò)的Javabean的引用,當(dāng)Web服務(wù)器關(guān)閉的時(shí)候,由于這個(gè)緩存中存放著這些Javabean的引用,所以垃圾回收器不能對(duì)Web容器中的JavaBean對(duì)象進(jìn)行回收,導(dǎo)致內(nèi)存越來(lái)越大。還有一點(diǎn)值得注意,清除Introspector緩存的唯一方式是刷新整個(gè)緩存緩沖區(qū),這是因?yàn)?code>JDK沒(méi)法判斷哪些是屬于當(dāng)前的應(yīng)用的引用,所以刷新整個(gè)Introspector緩存緩沖區(qū)會(huì)導(dǎo)致把服務(wù)器的所有應(yīng)用的Introspector緩存都刪掉。Spring中提供的org.springframework.web.util.IntrospectorCleanupListener就是為了解決這個(gè)問(wèn)題,它會(huì)在Web服務(wù)器停止的時(shí)候,清理一下這個(gè)Introspector緩存,使那些Javabean能被垃圾回收器正確回收。

也就是說(shuō)JDKIntrospector緩存管理是有一定缺陷的。但是如果使用在Spring體系則不會(huì)出現(xiàn)這種問(wèn)題,因?yàn)?code>Spring把Introspector緩存的管理移交到Spring自身而不是JDK(或者在Web容器銷(xiāo)毀后完全不管),在加載并分析完所有類(lèi)之后,會(huì)針對(duì)類(lèi)加載器對(duì)Introspector緩存進(jìn)行清理,避免內(nèi)存泄漏的問(wèn)題,詳情可以看CachedIntrospectionResultsSpringBoot刷新上下文的方法AbstractApplicationContext#refresh()finally代碼塊中存在清理緩存的方法AbstractApplicationContext#resetCommonCaches();。但是有很多程序和框架在使用了JavaBeans Introspector之后,都沒(méi)有進(jìn)行清理工作,比如Quartz、Struts等,這類(lèi)操作會(huì)成為內(nèi)存泄漏的隱患。 

到此,相信大家對(duì)“Java內(nèi)省Introspector相關(guān)類(lèi)有哪些”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI