前言

 implementation 'org.greenrobot:eventbus:3.0.0'
  • 1

前面一章介绍了通过implementation 添加依赖的执行过程,在build 阶段的时候gradle 就会下载对应的额依赖。本章主要研究依赖的下载过程。

一 下载依赖

Configuration 有一个resolve 方法。

    /*** Resolves this configuration. This locates and downloads the files which make up this configuration, and returns* the resulting set of files.** @return The files of this configuration.*/Set<File> resolve();

有英文注释可以知道,这个方法会定位并且下载对应的文件。

    public Set<File> resolve() {return getFiles();}
    public Set<File> getFiles() {return intrinsicFiles.getFiles();}

其中的intrinsicFiles 为ConfigurationFileCollection,在DefaultConfiguration 的构造方法里面初始化的。

ConfigurationFileCollection.java

        public Set<File> getFiles() {ResolvedFilesCollectingVisitor visitor = new ResolvedFilesCollectingVisitor();getSelectedArtifacts().visitArtifacts(visitor, lenient);if (!lenient) {rethrowFailure("files", visitor.getFailures());}return visitor.getFiles();}

getSelectedArtifacts 主要是获取当前Configuration 需要依赖的项。

implementation 'org.greenrobot:eventbus:+'

如果我们使用上面的写法,也就是没有使用具体的版本号,此时getSelectedArtifacts也会访问网络获取的这个依赖的最新版本。
如果存在依赖冲突问题getSelectedArtifacts方法内部可能会抛出异常。

        private SelectedArtifactSet getSelectedArtifacts() {if (selectedArtifacts == null) {assertResolvingAllowed();resolveToStateOrLater(ARTIFACTS_RESOLVED);selectedArtifacts = cachedResolverResults.getVisitedArtifacts().select(dependencySpec, viewAttributes, componentSpec, allowNoMatchingVariants);}return selectedArtifacts;}
    private void resolveToStateOrLater(InternalState requestedState) {assertResolvingAllowed();synchronized (resolutionLock) {if (requestedState == GRAPH_RESOLVED || requestedState == ARTIFACTS_RESOLVED) {//走这里resolveGraphIfRequired(requestedState);}if (requestedState == ARTIFACTS_RESOLVED) {resolveArtifactsIfRequired();}}}
    private void resolveGraphIfRequired(final InternalState requestedState) {//代码有删减resolver.resolveGraph(DefaultConfiguration.this, cachedResolverResults);}

此处的resolver 是DefaultConfigurationResolver

public void resolveGraph(ConfigurationInternal configuration, ResolverResults results) {//代码有删减resolver.resolve(configuration, resolutionAwareRepositories, metadataHandler, Specs.<DependencyMetadata>satisfyAll(), graphVisitor, artifactsVisitor, attributesSchema, artifactTypeRegistry);}这个resolver 是  DefaultArtifactDependencyResolver
    public void resolve(ResolveContext resolveContext, List<? extends ResolutionAwareRepository> repositories, GlobalDependencyResolutionRules metadataHandler, Spec<? super DependencyMetadata> edgeFilter, DependencyGraphVisitor graphVisitor, DependencyArtifactsVisitor artifactsVisitor, AttributesSchemaInternal consumerSchema, ArtifactTypeRegistry artifactTypeRegistry) {LOGGER.debug("Resolving {}", resolveContext);ComponentResolversChain resolvers = createResolvers(resolveContext, repositories, metadataHandler, artifactTypeRegistry);DependencyGraphBuilder builder = createDependencyGraphBuilder(resolvers, resolveContext.getResolutionStrategy(), metadataHandler, edgeFilter, consumerSchema, moduleIdentifierFactory, moduleExclusions, buildOperationExecutor);DependencyGraphVisitor artifactsGraphVisitor = new ResolvedArtifactsGraphVisitor(artifactsVisitor, resolvers.getArtifactSelector(), moduleExclusions);// Resolve the dependency graphbuilder.resolve(resolveContext, new CompositeDependencyGraphVisitor(graphVisitor, artifactsGraphVisitor));}


assembleResult 内部会遍历所有需要下载的依赖然后执行visitEdges方法

ResolvedArtifactsGraphVisitor.java

    @Overridepublic void visitEdges(DependencyGraphNode node) {for (DependencyGraphEdge dependency : node.getIncomingEdges()) {DependencyGraphNode parent = dependency.getFrom();//这是关键ArtifactsForNode artifacts = getArtifacts(dependency, node);artifactResults.visitArtifacts(parent, node, artifacts.artifactSetId, artifacts.artifactSet);}for (LocalFileDependencyMetadata fileDependency : node.getOutgoingFileEdges()) {int id = nextId++;artifactResults.visitArtifacts(node, fileDependency, id, artifactSelector.resolveArtifacts(fileDependency));}}


exclusions 应该就是在implementation 方法传递的过滤规则,这里没去仔细看过。

DefaultArtifactSelector.java

RepositoryChainArtifactResolver chain 记录的是在setting.gradle 里面配置的所有仓库。

可以看到是先在缓存里面查询,缓存不存在就去远程获取。
sourceRepository.getRemoteAccess()用于获取访问网络访问器,resolveArtifacts(unpackedComponent, result)用于获取依赖。

这里以RemoteRepositoryAccess 为例。由名字就知道RemoteRepositoryAccess 可以获取远程数据。

        @Overridepublic void resolveArtifact(ComponentArtifactMetadata artifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {ExternalResourceResolver.this.resolveArtifact(artifact, moduleSource, result);}

ExternalResourceResolver.java

    protected void resolveArtifact(ComponentArtifactMetadata componentArtifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {ModuleComponentArtifactMetadata artifact = (ModuleComponentArtifactMetadata) componentArtifact;File localFile;try {localFile = download(artifact, moduleSource, result);} catch (Throwable e) {result.failed(new ArtifactResolveException(artifact.getId(), e));return;}if (localFile != null) {result.resolved(localFile);} else {result.notFound(artifact.getId());}}
    protected File download(ModuleComponentArtifactMetadata artifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {LocallyAvailableExternalResource artifactResource = createArtifactResolver(moduleSource).resolveArtifact(artifact, result);if (artifactResource == null) {return null;}return artifactResource.getFile();}

createArtifactResolver 返回的是DefaultExternalResourceArtifactResolver

    public LocallyAvailableExternalResource resolveArtifact(ModuleComponentArtifactMetadata artifact, ResourceAwareResolveResult result) {if (artifact instanceof ModuleDescriptorArtifactMetadata) {return downloadStaticResource(ivyPatterns, artifact, result);}return downloadStaticResource(artifactPatterns, artifact, result);}
    private LocallyAvailableExternalResource downloadStaticResource(List<ResourcePattern> patternList, final ModuleComponentArtifactMetadata artifact, ResourceAwareResolveResult result) {for (ResourcePattern resourcePattern : patternList) {//获取需要下载的依赖ExternalResourceName location = resourcePattern.getLocation(artifact);result.attempted(location);LOGGER.debug("Loading {}", location);LocallyAvailableResourceCandidates localCandidates = locallyAvailableResourceFinder.findCandidates(artifact);try {LocallyAvailableExternalResource resource = resourceAccessor.getResource(location, new CacheAwareExternalResourceAccessor.ResourceFileStore() {public LocallyAvailableResource moveIntoCache(File downloadedResource) {return fileStore.move(artifact.getId(), downloadedResource);}}, localCandidates);if (resource != null) {return resource;}} catch (Exception e) {throw ResourceExceptions.getFailed(location.getUri(), e);}}return null;}

ExternalResourceName location 表示需要下载的来,resourceAccessor是CacheAwareExternalResourceAccessor,有名字可以直到,resourceAccessor会优先在缓存里面查找对应的依赖。如果缓存里面不存在,那么会DefaultExternalResourceRepository 的resource 方法下载资源。最终通过AccessorBackedExternalResource 的withContentIfPresent下载对应的依赖。

    private LocallyAvailableExternalResource copyToCache(final ExternalResourceName source, final ResourceFileStore fileStore, final ExternalResource resource) {// Download to temporary locationDownloadAction downloadAction = new DownloadAction(source);try {//resource 是AccessorBackedExternalResource  的代理类resource.withContentIfPresent(downloadAction);} catch (Exception e) {throw ResourceExceptions.getFailed(source.getUri(), e);}if (downloadAction.metaData == null) {return null;}// Move into cachetry {return moveIntoCache(source, downloadAction.destination, fileStore, downloadAction.metaData);} finally {downloadAction.destination.delete();}}
    @Nullable@Overridepublic <T> ExternalResourceReadResult<T> withContentIfPresent(Transformer<? extends T, ? super InputStream> transformer) throws ResourceException {try {//accessorExternalResourceReadResponse response = accessor.openResource(name.getUri(), revalidate);if (response == null) {return null;}try {CountingInputStream input = new CountingInputStream(new BufferedInputStream(response.openStream()));try {T value = transformer.transform(input);return ExternalResourceReadResult.of(input.getCount(), value);} finally {input.close();}} finally {response.close();}} catch (IOException e) {throw ResourceExceptions.getFailed(name.getUri(), e);}}

accessor 为HttpResourceAccessor,此时通过HttpResourceAccessor 打开网络连接,获取的输入流。

    @Override@Nullablepublic HttpResponseResource openResource(final URI uri, boolean revalidate) {String location = uri.toString();LOGGER.debug("Constructing external resource: {}", location);HttpClientResponse response = http.performGet(location, revalidate);if (response != null) {return wrapResponse(uri, response);}return null;}

http 为HttpClientHelper,HttpClientHelper 内部通过HttpClient 访问网络,关于Gradle 访问网络这一块就接收到这。

二、产物

前面介绍了Gradle 下载依赖的过程,可以知道Gradle 最终使用的是HttpClinet 网络框架下载的依赖文件,但是依赖文件下载之后还并不可以直接使用,例如 implementation ‘org.greenrobot:eventbus:3.0.0’ 下载下来是个aar文件,但android 最终需要的是包含源码的jar 文件,因此这里就需要解压等操作。这一步的操作名为Transform ,经过Transform 之后的文件我们称之为产物,也是我们最终最终依赖的文件。

        public Set<File> getFiles() {ResolvedFilesCollectingVisitor visitor = new ResolvedFilesCollectingVisitor();getSelectedArtifacts().visitArtifacts(visitor, lenient);if (!lenient) {rethrowFailure("files", visitor.getFailures());}return visitor.getFiles();}
        private SelectedArtifactSet getSelectedArtifacts() {if (selectedArtifacts == null) {assertResolvingAllowed();resolveToStateOrLater(ARTIFACTS_RESOLVED);selectedArtifacts = cachedResolverResults.getVisitedArtifacts().select(dependencySpec, viewAttributes, componentSpec, allowNoMatchingVariants);}return selectedArtifacts;}
    private void resolveToStateOrLater(InternalState requestedState) {assertResolvingAllowed();synchronized (resolutionLock) {if (requestedState == GRAPH_RESOLVED || requestedState == ARTIFACTS_RESOLVED) {resolveGraphIfRequired(requestedState);}if (requestedState == ARTIFACTS_RESOLVED) {resolveArtifactsIfRequired();}}}

resolveGraphIfRequired 是下载对应的依赖,这个在前面介绍了,resolveArtifactsIfRequired 会遍历下载的依赖文件然后进行转换。

    private void resolveArtifactsIfRequired() {if (resolvedState == ARTIFACTS_RESOLVED) {return;}if (resolvedState != GRAPH_RESOLVED) {throw new IllegalStateException("Cannot resolve artifacts before graph has been resolved.");}resolver.resolveArtifacts(DefaultConfiguration.this, cachedResolverResults);resolvedState = ARTIFACTS_RESOLVED;}
    public void resolveArtifacts(ConfigurationInternal configuration, ResolverResults results) {ArtifactResolveState resolveState = (ArtifactResolveState) results.getArtifactResolveState();ResolvedGraphResults graphResults = resolveState.graphResults;VisitedArtifactsResults artifactResults = resolveState.artifactsResults;TransientConfigurationResultsBuilder transientConfigurationResultsBuilder = resolveState.transientConfigurationResultsBuilder;TransientConfigurationResultsLoader transientConfigurationResultsFactory = new TransientConfigurationResultsLoader(transientConfigurationResultsBuilder, graphResults);DefaultLenientConfiguration result = new DefaultLenientConfiguration(configuration, resolveState.failures, artifactResults, resolveState.fileDependencyResults, transientConfigurationResultsFactory, artifactTransforms, buildOperationExecutor);results.artifactsResolved(new DefaultResolvedConfiguration(result), result);}

results 与下面截图中的cachedResolverResults是同一个对象。
results.artifactsResolved 仅仅是保存一些变量。

    @Overridepublic void artifactsResolved(ResolvedConfiguration resolvedConfiguration, VisitedArtifactSet visitedArtifacts) {this.resolvedConfiguration = resolvedConfiguration;this.visitedArtifacts = visitedArtifacts;this.artifactResolveState = null;}

此处需要知道的是VisitedArtifactSet visitedArtifacts实际是DefaultLenientConfiguration


在调用完resolveToStateOrLater之后会接着调用cachedResolverResults.getVisitedArtifacts().select 方法。其中cachedResolverResults.getVisitedArtifacts() 返回的就是上面创建的DefaultLenientConfiguration 对象。
下面接着看DefaultLenientConfiguration 的select 方法

    @Overridepublic SelectedArtifactSet select(final Spec<? super Dependency> dependencySpec, final AttributeContainerInternal requestedAttributes, final Spec<? super ComponentIdentifier> componentSpec, boolean allowNoMatchingVariants) {final SelectedArtifactResults artifactResults;//VariantSelector selector = artifactTransforms.variantSelector(requestedAttributes, allowNoMatchingVariants);artifactResults = this.artifactResults.select(componentSpec, selector);return new SelectedArtifactSet() {//代码有删减};}

这里面的artifactTransforms 用来产物转换,例如android插件内的AarTransform.
这个值是在构造DefaultConfigurationResolver确定的。其实际类型是DefaultArtifactTransforms。

artifactTransforms.variantSelector 返回AttributeMatchingVariantSelector 类型的一个变量,而this.artifactResults.select(componentSpec, selector)内部会调用AttributeMatchingVariantSelector 的select方法。

        @Overridepublic ResolvedArtifactSet select(ResolvedVariantSet producer) {try {return doSelect(producer);} catch (Throwable t) {return new BrokenResolvedArtifactSet(t);}}
        private ResolvedArtifactSet doSelect(ResolvedVariantSet producer) {AttributeMatcher matcher = schema.withProducer(producer.getSchema());List<? extends ResolvedVariant> matches = matcher.matches(producer.getVariants(), requested);List<Pair<ResolvedVariant, ConsumerVariantMatchResult.ConsumerVariant>> candidates = new ArrayList<Pair<ResolvedVariant, ConsumerVariantMatchResult.ConsumerVariant>>();for (ResolvedVariant variant : producer.getVariants()) {AttributeContainerInternal variantAttributes = variant.getAttributes().asImmutable();ConsumerVariantMatchResult matchResult = new ConsumerVariantMatchResult();//这个是核心matchingCache.collectConsumerVariants(variantAttributes, requested, matchResult);for (ConsumerVariantMatchResult.ConsumerVariant consumerVariant : matchResult.getMatches()) {candidates.add(Pair.of(variant, consumerVariant));}}if (candidates.size() == 1) {Pair<ResolvedVariant, ConsumerVariantMatchResult.ConsumerVariant> result = candidates.get(0);return new ConsumerProvidedResolvedVariant(result.getLeft().getArtifacts(), result.getRight().attributes, result.getRight().transformer);}}}

我们接着进入VariantAttributeMatchingCache 的collectConsumerVariants 方法

    public void collectConsumerVariants(AttributeContainerInternal actual, AttributeContainerInternal requested, ConsumerVariantMatchResult result) {AttributeSpecificCache toCache = getCache(requested);ConsumerVariantMatchResult cachedResult = toCache.transforms.get(actual);if (cachedResult == null) {cachedResult = new ConsumerVariantMatchResult();findProducersFor(actual, requested, cachedResult);toCache.transforms.put(actual, cachedResult);}cachedResult.applyTo(result);}


variantTransforms 里面保存的应该就是用户注册的转换器。


inputVariant.transformer.transform(file) 就会执行用户注册的转换器。下面我们以android 的ExtractAarTransform为例,ExtractAarTransform 主要是解压aar文件。

      override fun transform(outputs: TransformOutputs) {recordArtifactTransformSpan(parameters.projectName.get(),GradleTransformExecutionType.EXTRACT_AAR_ARTIFACT_TRANSFORM) {val inputFile = primaryInput.get().asFileval name = Files.getNameWithoutExtension(inputFile.name)val outputDir = outputs.dir(name)FileUtils.mkdirs(outputDir)val aarExtractor = AarExtractor()aarExtractor.extract(inputFile, outputDir)val classesJar = File(File(outputDir, FD_JARS), FN_CLASSES_JAR)if (!classesJar.exists()) {try {Files.createParentDirs(classesJar)FileOutputStream(classesJar).use { out ->// FileOutputStream above is the actual OS resource that will get closed,// JarOutputStream writes the bytes or an empty jar in it.val jarOutputStream = JarOutputStream(BufferedOutputStream(out), Manifest())jarOutputStream.close()}} catch (e: IOException) {throw RuntimeException("Cannot create missing classes.jar", e)}}}}

AarExtractor 的extract 方法会将aar 文件解压到指定的文件夹。android 插件里面还有一个AarTransform ,有感兴趣的可以自己看看。

总结

本文的内容到此就结束了,本篇主要粗略的介绍了一下Gradle 是如何下载依赖文件以及下载之后的转换操作,其实这对于我们的实际开发没什么作用,当初之所以看这一块主要是我想看看Gradle 是使用的什么网络框架。

转载:https://blog.csdn.net/qq_31469589/article/details/117414197

Android Gradle:依赖下载相关推荐

  1. Android Gradle依赖配置与依赖冲突解决

    #.Gradle依赖配置 ##.Gradle依赖管理与两个重要的classpath相关,每个Module都有: 1.编译时路径:compileClasspath 编译时能使用的代码,当一个类参与编译时 ...

  2. linux 搭建gradle android jenkins打包机器,gradle 依赖 jar问题

    app/build.gradle文件 apply plugin: 'com.android.application'android {compileSdkVersion 25buildToolsVer ...

  3. gradle项目 避免每次下载gradle文件/解决依赖下载慢的问题

    参考:https://www.jb51.net/article/114276.htm 避免每次下载gradle文件 一.使用已存在的 gradle 版本 打开目录 ~/.gradle/wrapper/ ...

  4. Android创建自己的gradle依赖包

    最近想把自己做过的一些东西分享给大家,请叫我高产小能手. Android创建自己的gradle依赖包 相信在用Android Studio的同学对gradle都不陌生吧: dependencies { ...

  5. Android:Gradle 依赖相关

    一:依赖配置 目前 Gradle 版本支持的依赖配置有:implementation.api.compileOnly.runtimeOnly 和 annotationProcessor 1)imple ...

  6. 【Android Gradle 插件】Android Plugin DSL Reference 离线文档下载 ( GitHub 下载文档 | 查看文档 )

    文章目录 一.Android Plugin DSL Reference 文档下载 二.Android Plugin DSL Reference 文档查看 一.Android Plugin DSL Re ...

  7. 【Android Gradle 插件】工程根目录下 build.gradle 配置文件 ( 远程仓库配置 | 依赖配置 | 所有子模块配置 | task clean 任务 )

    文章目录 一.工程根目录下 build.gradle 配置文件 1.基本作用 2.远程仓库配置 3.依赖配置 3.所有子模块配置 4.task clean 任务 Android Plugin DSL ...

  8. android studio的 gradle 依赖同步错误解决方法

    android studio的 gradle 依赖同步错误解决方法 参考文章: (1)android studio的 gradle 依赖同步错误解决方法 (2)https://www.cnblogs. ...

  9. cordova build android很慢,cordova build --release android命令打包下载gradle非常慢的问题...

    最近换了新电脑,重新安装开发环境,使用cordova build --release android命令打包时,需要下载gradle,等了半天cmd窗口中下载进度只打了两行点点,等得真是着急. 解决办 ...

最新文章

  1. 《繁凡的深度学习笔记》前言、目录大纲 一文让你完全弄懂深度学习所有基础(DL笔记整理系列)
  2. 客户端回传事件接口IPostBackEventHandler
  3. java的数值类型举例_Java基本类型(示例代码)
  4. 圆形和多边形雷达图python-Matplotlib绘制雷达图和三维图的示例代码
  5. 杰夫 · 贝佐斯:事情瞬息万变,需要马上行动
  6. Ionic+Angular实现中英国际化(附代码下载)
  7. [转] java.nio.ByteBuffer中flip、rewind、clear方法的区别
  8. linux如何设置mac快捷键,在Ubuntu上使用macOS的快捷键
  9. z变换判断稳定性和因果性_图像处理的仿射变换与透视变换
  10. iOS 计步器的几种实现方式
  11. python简述列表特征_python高级特性简介
  12. Linux集群和自动化维1.3 如何根据服务器应用选购服务器
  13. LeetCode刷题(36)--Text Justification
  14. JavaScript 是一种什么样的语言
  15. SQL Server中 缓冲和池的不同点
  16. java.util.concurrent.atomic原子操作类包
  17. 机器学习和ai哪个好_AI可以使您成为更好的运动员吗? 使用机器学习分析网球发球和罚球...
  18. 简谈触摸板程序的实现(一)
  19. 差点无缘Offer!java高并发编程详解深入理解pdf
  20. 单日峰值2T发送量邮件营销平台实践经验

热门文章

  1. sas数据集怎么导出_将多个SAS数据集转换为CSV文件
  2. Swift - 设置预编译宏
  3. Android11.0默认打开允许安装未知源开关
  4. 鉴赏百度指数,打造自己的爆款数据产品
  5. Android多媒体框架(3)—— libstagefright中MediaCodec源码分析
  6. 什么是字面量?(小白理解
  7. 利用文本编辑器判断dll/exe是否为64位
  8. linux安装cmake
  9. html页面改成jsp后IE和360浏览器不兼容问题
  10. PAT乙级题解1005(超级详细分析,看完就懂)