spring之class讀取生成元數(shù)據(jù)流程

描述

在ClassPathBeanDefinitionScanner中看到spring通過掃描給定的包路徑,獲取到對應(yīng)的class資源并判斷是否生成BeanDefinition注冊到IOC容器中逼裆,接下來根據(jù)源碼來看spring是怎么通過class資源生成元數(shù)據(jù)

ClassPathBeanDefinitionScanner分析中看到 MetadataReaderFactory.getMetadataReader方法通過class資源(resource)生成MetadataReader

    // 此處通過asm將class文件讀取成元數(shù)據(jù)模型
    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

下面跟讀MetadataReaderFactory與MetadataReader代碼查看class生成元數(shù)據(jù)。

MetadataReaderFactory

MetadataReaderFactory接口 ,MetadataReader的工廠接口抖锥。
允許緩存每個MetadataReader的元數(shù)據(jù)集碎罚。

  • 類關(guān)系圖
metaReaderFactory.png
public interface MetadataReaderFactory {
    /**
     * 根據(jù)class名稱創(chuàng)建MetadataReader
     */
    MetadataReader getMetadataReader(String className) throws IOException;

    /**
     * 根據(jù)class的Resource創(chuàng)建MetadataReader
     */
    MetadataReader getMetadataReader(Resource resource) throws IOException;

}

MetadataReaderFactory接口提供兩個方法:

  1. 根據(jù)class名稱生成MetadataReader
  2. 根據(jù)class的Resource生成MetadataReader
  • SimpleMetadataReaderFactory
public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
    // 資源加載器磅废,此類根據(jù)路徑將給定的path生成IO流資源
    private final ResourceLoader resourceLoader;
    @Override
    public MetadataReader getMetadataReader(String className) throws IOException {
        try {
            //根據(jù)classname生成class對應(yīng)的資源路徑
            String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
            //獲取classname的IO流資源     
            Resource resource = this.resourceLoader.getResource(resourcePath);
            //調(diào)用資源創(chuàng)建MetadataReader
            return getMetadataReader(resource);
        }
        catch (FileNotFoundException ex) {
        }
    }
    
    /**
     *  根據(jù)class資源創(chuàng)建MetadataReader 默認(rèn)實(shí)現(xiàn)
     */
    @Override
    public MetadataReader getMetadataReader(Resource resource) throws IOException {
        return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
    }

}

SimpleMetadataReaderFactory類為MetadataReaderFactory的簡單實(shí)現(xiàn),默認(rèn)實(shí)現(xiàn)了MetadataReaderFactory的兩個方法

  • 在getMetadataReader(String className) 方法中根據(jù)className創(chuàng)建class的Resource荆烈,然后調(diào)用getMetadataReader(Resource resource)
  • 在getMetadataReader(Resource resource) 方法中默認(rèn)創(chuàng)建了SimpleMetadataReader
  • CachingMetadataReaderFactory
public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
    //默認(rèn)的緩存大小
    public static final int DEFAULT_CACHE_LIMIT = 256;
    //內(nèi)存緩存列表拯勉,Resource-MetadataReader的映射緩存
    @Nullable
    private Map<Resource, MetadataReader> metadataReaderCache;
    
    @Override
    public MetadataReader getMetadataReader(Resource resource) throws IOException {
        if (this.metadataReaderCache instanceof ConcurrentMap) {
        
            MetadataReader metadataReader = this.metadataReaderCache.get(resource);
            if (metadataReader == null) {
                metadataReader = super.getMetadataReader(resource);
                //緩存到本地緩存
                this.metadataReaderCache.put(resource, metadataReader);
            }
            return metadataReader;
        }
        else if (this.metadataReaderCache != null) {
            synchronized (this.metadataReaderCache) {
                MetadataReader metadataReader = this.metadataReaderCache.get(resource);
                if (metadataReader == null) {
                    metadataReader = super.getMetadataReader(resource);
                //緩存到本地緩存   this.metadataReaderCache.put(resource, metadataReader);
                }
                return metadataReader;
            }
        }
        else {
            return super.getMetadataReader(resource);
        }
    }
}

CachingMetadataReaderFactory 類在SimpleMetadataReaderFactory的基礎(chǔ)上增加了緩存功能,對Resource-MetadataReader的映射做了本地緩存

MetadataReader

spring 對MetadataReader的描述為:Simple facade for accessing class metadata,as read by an ASM.大意是通過ASM讀取class IO流資源組裝訪問元數(shù)據(jù)的門面接口

  • 類關(guān)系圖
MetadataReader.png
  • MetadataReader
public interface MetadataReader {

    /**
     * 返回class文件的IO資源引用
     */
    Resource getResource();

    /**
     * 為基礎(chǔ)class讀取基本類元數(shù)據(jù)憔购,返回基礎(chǔ)類的元數(shù)據(jù)宫峦。
     */
    ClassMetadata getClassMetadata();

    /**
     *為基礎(chǔ)類讀取完整的注釋元數(shù)據(jù),包括注釋方法的元數(shù)據(jù)玫鸟。返回基礎(chǔ)類的完整注釋元數(shù)據(jù)
     */
    AnnotationMetadata getAnnotationMetadata();
}

MetadataReader接口提供三個方法:

  1. 返回class文件的IO資源引用
  2. 返回基礎(chǔ)類的元數(shù)據(jù)
  3. 返回基礎(chǔ)類的完整注釋元數(shù)據(jù)
  • SimpleMetadataReader
final class SimpleMetadataReader implements MetadataReader {

    //class類IO流資源引用
    private final Resource resource;

     //class類元數(shù)據(jù)
    private final ClassMetadata classMetadata;
     //class類完整注釋元數(shù)據(jù)
    private final AnnotationMetadata annotationMetadata;

    /**
     * 構(gòu)建函數(shù)导绷,用于通過過ASM字節(jié)碼操控框架讀取class讀取class資源流
     */
    SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
        // 獲取class類IO流
        InputStream is = new BufferedInputStream(resource.getInputStream());
        ClassReader classReader;
        try {
            //通過ASM字節(jié)碼操控框架讀取class
            classReader = new ClassReader(is);
        }
        catch (IllegalArgumentException ex) {
        }
        finally {
            is.close();
        }

        //注解元數(shù)據(jù)讀取訪問者讀取注解元數(shù)據(jù)
        AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
        classReader.accept(visitor,ClassReader.SKIP_DEBUG);
        //注解元數(shù)據(jù)
        this.annotationMetadata = visitor;
        //class元數(shù)據(jù)
        this.classMetadata = visitor;
        this.resource = resource;
    }


    @Override
    public Resource getResource() {
        return this.resource;
    }

    @Override
    public ClassMetadata getClassMetadata() {
        //返回當(dāng)前類元數(shù)據(jù)
        return this.classMetadata;
    }

    @Override
    public AnnotationMetadata getAnnotationMetadata() {
        //返回當(dāng)前類的注解元數(shù)據(jù)
        return this.annotationMetadata;
    }

}

SimpleMetadataReader 為MetadataReader的默認(rèn)實(shí)現(xiàn),在創(chuàng)建SimpleMetadataReader通過ASM字節(jié)碼操控框架讀取class讀取class資源流生成classMetadata與annotationMetadata

元數(shù)據(jù)模型

類元數(shù)據(jù)模型在包org.springframework.core.type下屎飘,是spring對class文件的描述單元妥曲,包含ClassMetadata,MethodMetadata钦购,AnnotationMetadata等元數(shù)據(jù)檐盟,都是對外提供對class屬性的訪問,同時這些元數(shù)據(jù)是通過ASM字節(jié)碼框架解析字節(jié)碼獲取生成押桃。

  • ClassMetadata

提供對class類的信息訪問

public interface ClassMetadata {

   //返回當(dāng)前class名稱
    String getClassName();
   //返回當(dāng)前class是否為接口
    boolean isInterface();
    //返回當(dāng)前class是否為注解
    boolean isAnnotation();
    //返回當(dāng)前class是否為抽象類
    boolean isAbstract();

    boolean isConcrete();
    //返回當(dāng)前class是否為final修飾
    boolean isFinal();

    boolean isIndependent();

    boolean hasEnclosingClass();

    String getEnclosingClassName();

    boolean hasSuperClass();

    String getSuperClassName();

    String[] getInterfaceNames();

    String[] getMemberClassNames();

}
  • AnnotationMetadata

提供對class類里的注解信息訪問

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

    Set<String> getAnnotationTypes();

    Set<String> getMetaAnnotationTypes(String annotationName);

    boolean hasAnnotation(String annotationName);

    boolean hasMetaAnnotation(String metaAnnotationName);

    boolean hasAnnotatedMethods(String annotationName);

    Set<MethodMetadata> getAnnotatedMethods(String annotationName);

}
  • MethodMetadata

提供對class類里方法信息的訪問

public interface MethodMetadata extends AnnotatedTypeMetadata {
    String getMethodName();
    String getDeclaringClassName();
    String getReturnTypeName();
    boolean isAbstract();
    boolean isStatic();
    boolean isFinal();
    boolean isOverridable();

}

通過ClassPathBeanDefinitionScanner與生成元數(shù)據(jù)流程部分我們可以看到spring對class的完整操作

  1. 將class文件生成IO流的Resource
  2. 通過ASM字節(jié)碼框架根據(jù)Resource創(chuàng)建元數(shù)據(jù)模型
  3. 根據(jù)元數(shù)據(jù)模型以及Resource生成BeanDefinition(bean定義)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葵萎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子怨规,更是在濱河造成了極大的恐慌陌宿,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件波丰,死亡現(xiàn)場離奇詭異壳坪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掰烟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門爽蝴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纫骑,你說我怎么就攤上這事蝎亚。” “怎么了先馆?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵发框,是天一觀的道長。 經(jīng)常有香客問我煤墙,道長梅惯,這世上最難降的妖魔是什么宪拥? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮铣减,結(jié)果婚禮上她君,老公的妹妹穿的比我還像新娘。我一直安慰自己葫哗,他們只是感情好缔刹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劣针,像睡著了一般校镐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酿秸,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天灭翔,我揣著相機(jī)與錄音,去河邊找鬼辣苏。 笑死肝箱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的稀蟋。 我是一名探鬼主播煌张,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼退客!你這毒婦竟也來了骏融?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤萌狂,失蹤者是張志新(化名)和其女友劉穎档玻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茫藏,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡误趴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了务傲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凉当。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖售葡,靈堂內(nèi)的尸體忽然破棺而出看杭,到底是詐尸還是另有隱情,我是刑警寧澤挟伙,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布楼雹,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏烘豹。R本人自食惡果不足惜瓜贾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望携悯。 院中可真熱鬧,春花似錦筷笨、人聲如沸憔鬼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轴或。三九已至,卻和暖如春仰禀,著一層夾襖步出監(jiān)牢的瞬間照雁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工答恶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饺蚊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓悬嗓,卻偏偏與公主長得像污呼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子包竹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容