Glide源码解析篇之框架主体结构(一)

来源:互联网 发布:2017最新淘宝口令红包 编辑:程序博客网 时间:2024/05/01 20:54
      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生成了些什么代码。

阅读这篇文章需要对annotation process tool 有所了解,如果不知道的朋友可以先看我的另一篇文章:http://blog.csdn.net/qq_28029345/article/details/78543950   

        在这之前,为了能在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代码为什么这么设计,好处在哪里?开发项目中能否借鉴?到时候,还请读了此文的朋友多多关注。