1. 程式人生 > >Glide原始碼解析篇之框架主體結構(一)

Glide原始碼解析篇之框架主體結構(一)

      Gide作為Android最受歡迎的圖片載入庫之一,一直深受Android開發者的喜愛,很大原因就是它的功能極其強大,而使用卻異常簡單。無論是網路、快取、特效,佔位圖,Glide團隊都為開發者考慮的非常細緻,也正因為這個原因,Glide框架的原始碼變得極其複雜,生澀難懂,我觀察到網上有寫原始碼分析的某大神光寫主體結構的程式碼分析都寫了兩個禮拜,可見Glide的原始碼複雜程度超乎了很多程式設計師們的想象。不過複雜歸複雜,其整個脈絡還是很清晰的,從這邊文章開始,我們將從整體到區域性來研究Glide的原始碼。      既然研究原始碼,當然是越新越好,我們看到https://github.com/bumptech/glide,glide版本在今天已經更新到了4.3.1,這裡就分析4.3.1的原始碼。

        我們看到glide團隊的迭代非常頻繁,2天前還有提交程式碼,所以我覺得時刻保持學習的心是非常重要的,並且不光要看人家程式碼是怎麼實現的,還要看人家的整體設計思想,這樣自身才會成長。         首先我們為了研究原始碼可以建立一個android專案,引入glide4.3.1的庫,配置如下:          dependencies {                       compile 'com.github.bumptech.glide:glide:4.3.1
'                       annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1 }         看到這段配置,熟悉的感覺來了,annotationProcessor  編譯器註解生成器,我們看到glide的新版本也引入了apt庫,看到這裡,我的好奇心來了,一定得弄明白glide生成了些什麼程式碼。         在這之前,為了能在External Libraryies中檢視com.github.bumptech.glide:compiler:4.3.1 這個包,我把  annotationProcessor
'com.github.bumptech.glide:compiler:4.3.1’ 臨時改成 compile 'com.github.bumptech.glide:compiler:4.3.1’ ,然後我們看到glide總共有5個java庫,如下:
        我特意去看了下glide老版本:
        在glide3.5.2中就只有一個jar, Glide把快取演算法程式碼,gif解碼程式碼全部放在了一個jar裡,老版也沒有apt這個概念,在老版中如果要配置GlideModule,需要在AndroidManifest.xml中宣告,指向一個使用者自定義的一個GlideModule類,在這個類相當於Glide配置類。         在glide4.3.1中,我們看到了整整5個java庫,這5個庫分別是幹嘛的從字面上都很好理解。我覺得glide團隊把快取演算法與gif解碼抽取出來都是為了模組化,無論是把這些庫用到別的地方,還是將更先進的演算法引入都是非常便利的,而主體的glide包不用做任何修改,而引入apt則是進一步讓使用者感覺不到框架的存在,為什麼呢?我們對比另一個開源框架ImageLoader庫想一想就知道了,ImageLoader使用前需要初始化,在Application中呼叫init()然後各種配置,而Glide你會發現無需配置,因為就算你不建立GlideModule,他自身就有一套預設的配置,而且在你不使用Glide.with()的時候根本不會初始化,實現了懶載入。即使需要自定義,在老版的glide中只需要在AndroidManifest.xml 中配置,在建立一個類即可,而新版則更進一步,只要建立一個GlideModule類再加一個註解即可完成整個自定義配置,無需配置AndroidManifest.xml,讓使用者對Glide框架的存在感進一步拉小,這就是Glide新版引入apt的原因所在。
        由於我打算全方位的解析Glide原始碼,所以我的第一篇文章不打算講Glide的執行流程,而是先從compiler包究竟生成了些什麼說起,在Glide框架中生成的這些類的作用,然後再進入Glide原始碼一步步分析Glide的整個執行流程,在流程中探討為什麼Glide團隊會這麼寫。
    下面先來看:
 

 我們看到GlideModule註解,然後再看AppModuleProcessor 就知道只要在某個類上使用GlideModule註解,而且這個類必然存在一個模板類讓我們繼承,並且一定會在編譯期生成相應的類。 我們不妨一試: package com.xhl.myapplication; import com.bumptech.glide.annotation.GlideModule; import com.bumptech.glide.module.AppGlideModule; /** * Created by xuhongliang on 2017/11/17. */ @GlideModule public class GlideModuleExample extends AppGlideModule { } 我們定義一個類繼承自AppGlideModule,這個AppGlideModule是glide提供的,我們不用關心,因為要使用GlideModule這個註解,必須繼承Glide所提供的某個類,這裡就繼承AppGlideModule了,然後我們編譯一下程式碼,看一下生成了什麼。
我們看到了一個@GlideModule註解 ,在build目錄下生成了6個java類,從字面上我們理解一下: GeneratedAppGlideModuleImpl 模組配置相關類,在Glide初始化的時候肯定會建立這個類的物件。 GeneratedRequestManagerFactory 請求管理器工廠,肯定是生成請求管理器的。 GlideApp 應該與Glide類的功能大同小異, GlideOptions Glide的配置資訊,包括儲存placeholder,errorholder的drawable資源等等。 GlideRequest與GildeRequests很顯然要麼是包含關係,要麼GlideRequests是GlideRequest的管理者。 先看GeneratedAppGlideModuleImpl @SuppressWarnings("deprecation") final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule {   private final GlideModuleExample appGlideModule; GeneratedAppGlideModuleImpl() {     appGlideModule = new GlideModuleExample();     if (Log.isLoggable("Glide", Log.DEBUG)) {       Log.d("Glide","Discovered AppGlideModule from annotation: com.xhl.myapplication.GlideModuleExample"); }   }   @Override public voidapplyOptions(Context context, GlideBuilder builder) {     appGlideModule.applyOptions(context, builder); }   @Override public voidregisterComponents(Context context, Glide glide, Registry registry) {     appGlideModule.registerComponents(context, glide, registry); }   @Override public booleanisManifestParsingEnabled() {     return appGlideModule.isManifestParsingEnabled(); }   @Override public Set<Class<?>>getExcludedModuleClasses() {     return Collections.emptySet(); }   @Override GeneratedRequestManagerFactory getRequestManagerFactory() {     return new GeneratedRequestManagerFactory(); } } 我們看到這個類中包含了我們定義個配置類GlideModuleExample,在這裡建立了我們自定義的配置類,並且執行了配置,同時還可以得到請求管理器的工廠物件,GeneratedRequestManagerFactory 這個工廠也是自動生成的,我們進GeneratedRequestManagerFactory看一下: final class GeneratedRequestManagerFactoryimplements RequestManagerRetriever.RequestManagerFactory {   @Override public RequestManagerbuild(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, Context context) {     return new GlideRequests(glide, lifecycle, treeNode, context); } } 請求管理工廠可以生成請求管理者,而GlideRequests繼承自RequestManager,所以先梳理下類關係
      上面這張UML圖已經把生成出來的類關係大致描述清楚了,生成的GeneratedAppGlideModuleImpl 也繼承了AppGlideModule,所以GeneratedAppGlideModuleImpl使用了下裝飾者設計模式,擴充套件了一個getRequestManagerFactory方法,而這個工廠則可以建立請求管理者並建立維護GlideRequest。從程式碼上來看我們Glide類中最終建立了GlideModuleExample類,並將Glide自身傳給這個類,在建立GlideRequests這個請求管理者時也將Glide類自身物件傳了進去,所以整個框架中Glide物件無處不在,我們姑且分析到這,不再往下深究,至於究竟這些類派到了什麼用場,等到講Glide執行過程中才需要去明白,這裡只需要有個印象,我們可以簡單的去推測下這些類的用途,去思考下為什麼要這麼設計。        目前階段我們不去關注Glide是怎麼實現的,而是從apt入手,去猜測Glide團隊的用意,我覺得這種啟發性的閱讀比直接觀看原始碼更有意義,因為優秀的開原始碼不在於看懂,而是要學其精髓,學其思想,學習人家這樣設計的好處在哪裡?至於Glide裡邊的程式碼實現我覺得反而是次要的。       現在我們來看compiler包下的生成器,在之前,我們來列出glide所有註解               其中GlideModule我們已經使用過了,使用這個註解可以生成6個java物件。其他註解的作用我們一一看來。
1,Index 註解 @Target(ElementType.TYPE) // Needs to be parsed from class files in JAR. @Retention(RetentionPolicy.CLASS) @interface Index {   String[] modules() default {}; String[] extensions()default {}; } 這個註解是位元組碼級別的位元組,一般宣告這類級別的註解是需要使用諸如asm這類工具來修改java位元組碼的,不過同樣可以使用apt處理。 我想這邊也只用了apt來處理。在compiler中又AppModuleProccessor中對Index註解有處理,也驗證了我的想法。 2,Excludes 註解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interfaceExcludes {   Class[] value(); } 這個註解是執行時註解,猜測Glide框架用於執行時反射獲得值,同時照樣可以由apt處理。 3,GlideExtension @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interfaceGlideExtension { } 這個註解生成了GlideOptions, 是怎麼知道的呢,看GlideOptions上面的註釋。 Automatically generated from {@linkcom.bumptech.glide.annotation.GlideExtension} annotated classes. 4,GlideModule @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interfaceGlideModule { String glideName() default "GlideApp"; } 這個註解已經使用過 不解釋了,不過在這裡我偶然發現前面為何會生成GlideApp這個類了,原來這個註解裡包含著一個預設值GlideApp,這個名稱也就是所生成類的名字。 5, GlideOption @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interfaceGlideOption { intOVERRIDE_NONE = 0; intOVERRIDE_EXTEND = 1; intOVERRIDE_REPLACE = 2; intoverride() defaultOVERRIDE_NONE; String staticMethodName() default “"; booleanmemoizeStaticMethod() default false;
booleanskipStaticMethod() default false; } 這個註解與GlideExtension一起生成了GlideRequest()同樣有註釋 * {@linkcom.bumptech.glide.annotation.GlideOption} in annotated methods in * {@linkcom.bumptech.glide.annotation.GlideExtension} annotated classes. 6,GlideType @Target(ElementType.METHOD) // Needs to be parsed from class files in JAR. @Retention(RetentionPolicy.CLASS) public @interfaceGlideType { Class<?> value(); } 這個註解與GlideExtension一起生成了GlideRequests * Includes all additions from methods in {@linkcom.bumptech.glide.annotation.GlideExtension}s * annotated with {@linkcom.bumptech.glide.annotation.GlideType} 以上註解我們大概猜一下用處不必深究。我們來看重點compiler包
annotation.compiler下全部都是註解生成器或與之相關的。 repackaged.com是apt所需要用到的第三方庫,這裡把他們都打在一個jar裡了,很方便。 java程式碼生成的原理都一樣,只是我們不知道為什麼需要生成,究竟生成他有什麼好處,這裡我們只能從側面去推敲一下,先挑一個看一下程式碼。我們找個熟悉的類來看,AppModuleProcessor,發現並不是起始的處理器,然後開啟簡單看一下,發現所有的類的生成器全部找到了,由於不是apt主入口,我們切換到主類去,發現GlideAnnotationProcessor才是入口類。 final class AppModuleProcessor { AppModuleProcessor(ProcessingEnvironment processingEnv, ProcessorUtil processorUtil) {      //appModule生成器—生成了GeneratedAppGlideModuleImpl appModuleGenerator =new AppModuleGenerator(processorUtil);    //RequestOptions生成器 —生成了 RequestOptions requestOptionsGenerator =new RequestOptionsGenerator(processingEnv, processorUtil);    //RequestManagerGenerator生成器— 生成了GlideRequests requestManagerGenerator =new RequestManagerGenerator(processingEnv, processorUtil);   //RequestManagerFactoryGenerator生成器 — 生成了GeneratedMananerFactory requestManagerFactoryGenerator =new RequestManagerFactoryGenerator(processingEnv);   //GlideGenerator生成器— 生成了GlideApp glideGenerator =new GlideGenerator(processingEnv, processorUtil);   //RequestBuilderGenerator生成器—  生成了GlideRequest requestBuilderGenerator =new RequestBuilderGenerator(processingEnv, processorUtil); } } 開啟GlideAnnotationProcessor AutoService(Processor.class) public final class GlideAnnotationProcessorextends AbstractProcessor {   static final boolean DEBUG = false;   private ProcessorUtil processorUtil;   private LibraryModuleProcessor libraryModuleProcessor;   private AppModuleProcessor appModuleProcessor;   private boolean isGeneratedAppGlideModuleWritten;   private ExtensionProcessor extensionProcessor; @Override public synchronized voidinit(ProcessingEnvironment processingEnvironment) {     super.init(processingEnvironment); processorUtil =new ProcessorUtil(processingEnvironment); IndexerGenerator indexerGenerator = new IndexerGenerator(processorUtil); libraryModuleProcessor =new LibraryModuleProcessor(processorUtil, indexerGenerator); appModuleProcessor =new AppModuleProcessor(processingEnvironment,processorUtil); extensionProcessor =new ExtensionProcessor(processorUtil, indexerGenerator); }   @Override public Set<String>getSupportedAnnotationTypes() {     Set<String> result = new HashSet<>(); result.addAll(libraryModuleProcessor.getSupportedAnnotationTypes()); result.addAll(extensionProcessor.getSupportedAnnotationTypes());     return result; } @Override public booleanprocess(Set<? extends TypeElement> set, RoundEnvironment env) {     processorUtil.process();     boolean newModulesWritten = libraryModuleProcessor.processModules(set, env);     boolean newExtensionWritten = extensionProcessor.processExtensions(set, env); appModuleProcessor.processModules(set, env);     if (newExtensionWritten || newModulesWritten) {       if (isGeneratedAppGlideModuleWritten) {         throw new IllegalStateException("Cannot process annotations after writing AppGlideModule"); }       return true; }     if (!isGeneratedAppGlideModuleWritten) {       isGeneratedAppGlideModuleWritten = appModuleProcessor.maybeWriteAppModule(); }     return true; } } 熟悉的程式碼來了,getSupportedAnnotationTypes獲取需要處理的註解類集合,從LibraryModuleProcessor與ExtensionProcessor中獲取 final class LibraryModuleProcessor {   Set<String> getSupportedAnnotationTypes() {
    return Collections.singleton(GlideModule.class.getName()); } } final class ExtensionProcessor{ Set<String> getSupportedAnnotationTypes() {   return Collections.singleton(GlideExtension.class.getName()); } 我們看到實際上註解處理器只註冊了兩個註解,一個是GlideModule,一個是GlideExtension,一旦在專案中我們沒有使用它們,這個註解處理器是不會執行任何程式碼處理的,也就不會生成與之相關的所有類,所以如果我們在專案中如果沒有使用這兩個註解,那麼Glide肯定會用框架中預設的一套配置處理圖片載入,一旦加入了這個註解,那所生成的類對於Glide就相當於裝了一個外掛,改變了Glide內部的預設配置,到這裡其實我們的研究就可以停止了,因為已經知道這些生成的程式碼並不是框架所必需的,研究下去只是鞏固了下apt知識而已,下面就簡單的分析一下compiler處理吧,不過多解釋了,下篇開始就來閱讀Glide框架程式碼,從入口開始一步一步往深層探究。 繼續看GlideAnnotationProcessor的核心方法process(),      boolean newModulesWritten = libraryModuleProcessor.processModules(set, env);     boolean newExtensionWritten = extensionProcessor.processExtensions(set, env); appModuleProcessor.processModules(set, env);     if (newExtensionWritten || newModulesWritten) {       if (isGeneratedAppGlideModuleWritten) {         throw new IllegalStateException("Cannot process annotations after writing AppGlideModule"); }       return true; }     if (!isGeneratedAppGlideModuleWritten) {       isGeneratedAppGlideModuleWritten = appModuleProcessor.maybeWriteAppModule(); } 這裡的生成器都是一樣的,這裡只看AppGlideModule吧 在核心處理中我們呼叫了appModuleProcessor.processModules(set, env) void processModules(Set<?extends TypeElement> set, RoundEnvironment env) { //判斷元素上是否有GlideModule註解    for (TypeElement element : processorUtil.getElementsFor(GlideModule.class, env)) {     //如果是屬於appGlideModule,則加入集合
     if (processorUtil.isAppGlideModule(element)) {        appGlideModules.add(element); }    }   processorUtil.debugLog("got app modules: " +appGlideModules);   if (appGlideModules.size() >1) {     throw new IllegalStateException(         "You cannot have more than one AppGlideModule, found: " +appGlideModules); } } 然後呼叫了 appModuleProcessor.maybeWriteAppModule(); 看具體實現: boolean maybeWriteAppModule() { if (appGlideModules.isEmpty()) {     return false; }   TypeElement appModule = appGlideModules.get(0); processorUtil.debugLog("Processing app module: " + appModule); PackageElement glideGenPackage =       processingEnv.getElementUtils().getPackageElement(COMPILER_PACKAGE_NAME); FoundIndexedClassNames indexedClassNames = getIndexedClassNames(glideGenPackage); String generatedCodePackageName = appModule.getEnclosingElement().toString(); TypeSpec generatedRequestOptions =         requestOptionsGenerator.generate(generatedCodePackageName, indexedClassNames.extensions); writeRequestOptions(generatedCodePackageName, generatedRequestOptions); TypeSpec generatedRequestBuilder =       requestBuilderGenerator.generate(generatedCodePackageName, generatedRequestOptions); writeRequestBuilder(generatedCodePackageName, generatedRequestBuilder); TypeSpec requestManager =       requestManagerGenerator.generate(           generatedCodePackageName, generatedRequestOptions, generatedRequestBuilder, indexedClassNames.extensions); writeRequestManager(generatedCodePackageName, requestManager); TypeSpec requestManagerFactory =       requestManagerFactoryGenerator.generate(generatedCodePackageName, requestManager); writeRequestManagerFactory(requestManagerFactory); TypeSpec glide =       glideGenerator.generate(generatedCodePackageName, getGlideName(appModule), requestManager); writeGlide(generatedCodePackageName, glide); TypeSpec generatedAppGlideModule =       appModuleGenerator.generate(appModule, indexedClassNames.glideModules); processorUtil.infoLog("Wrote GeneratedAppGlideModule with: " + indexedClassNames.glideModules);   return true; } 然後呼叫 private void writeAppModule(TypeSpec appModule) {   processorUtil.writeClass(AppModuleGenerator.GENERATED_ROOT_MODULE_PACKAGE_NAME, appModule); } 最終生成了我們最初看到的那些類,具體的實現就是上述程式碼,無非就是建立一個TypeSpec類,加欄位,加方法,加包名,加描述等等,然後寫入filer即完成生成。 void writeClass(String packageName, TypeSpec clazz) {   try {     debugLog("Writing class:\n" + clazz); JavaFile.builder(packageName, clazz).build().writeTo(processingEnv.getFiler()); } catch (Throwable e) {     throw new RuntimeException(e); } } 以上是compiler的一個處理過程,不過多研究了,上面已經有解釋,等到研究框架原始碼的時候可以回過頭來看下apt生成的這些程式碼對於框架來說究竟起到了一個什麼作用,現在我們只是在井裡觀天,等爬出井外遊玩一番我們在來觀察這口井,下篇開始要進入真正的Glide原始碼解析,並且會詳細探索Glide程式碼為什麼這麼設計,好處在哪裡?開發專案中能否借鑑?到時候,還請讀了此文的朋友多多關注。