parent
822948d301
commit
9b49696fbb
@ -0,0 +1,241 @@ |
|||||||
|
--- |
||||||
|
深入理解 Gradle 框架之 依赖实现分析 |
||||||
|
--- |
||||||
|
|
||||||
|
> 本文摘自:@ AllenWang [深入理解gradle框架之二:依赖实现分析](https://mp.weixin.qq.com/s/WQCqUaYDPHDIjUHlxjRIkw) |
||||||
|
|
||||||
|
### 目录 |
||||||
|
|
||||||
|
1. 引言 |
||||||
|
2. 从 implementation 说起 |
||||||
|
|
||||||
|
### 引言 |
||||||
|
|
||||||
|
大家在日常开发中,见过最多的可能就是下面三种依赖声明: |
||||||
|
|
||||||
|
```groovy |
||||||
|
implementation “org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version” |
||||||
|
implementation project(":applemodule") |
||||||
|
implementation fileTree(dir:‘libs’, include:[’*.jar’]) |
||||||
|
``` |
||||||
|
|
||||||
|
这些不同的依赖声明,内部实现机制是怎么样的? |
||||||
|
|
||||||
|
### 从 implementation 说起 |
||||||
|
|
||||||
|
``` |
||||||
|
implementation 'com.android.support:appcompat-v7:28.0.0' |
||||||
|
``` |
||||||
|
|
||||||
|
按照 Groovy 的语法,这里要执行的是 DependencyHandler 的 implementation() 方法,参数为 'com.android.support:appcompat-v7:28.0.0'。 |
||||||
|
|
||||||
|
但是在 DependencyHandler 中并没有 implementation() 这个方法,这是怎么回事呢? |
||||||
|
|
||||||
|
```java |
||||||
|
public interface DependencyHandler { |
||||||
|
|
||||||
|
Dependency add(String configurationName, Object dependencyNotation); |
||||||
|
|
||||||
|
Dependency create(Object dependencyNotation); |
||||||
|
|
||||||
|
Dependency module(Object notation); |
||||||
|
|
||||||
|
Dependency project(Map<String, ?> notation); |
||||||
|
|
||||||
|
Dependency gradleApi(); |
||||||
|
|
||||||
|
Dependency localGroovy(); |
||||||
|
|
||||||
|
//... |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
#### MethodMissing |
||||||
|
|
||||||
|
这其实涉及到了 Groovy 语言的一个重要特性:methodMissing,这个特性允许在运行时 catch 对于未定义方法的调用。 |
||||||
|
|
||||||
|
Gradle 对这个特性进行封装,一个类要想使用这个特性,只要实现 MixIn 接口即可,这个接口如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public interface MethodMixIn { |
||||||
|
MethodAccess getAdditionalMethods(); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
其中 MethodAccess 接口如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public interface MethodAccess { |
||||||
|
boolean hasMethod(String var1, Object... var2); |
||||||
|
|
||||||
|
DynamicInvokeResult tryInvokeMethod(String var1, Object... var2); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
也就是说,对于 DependencyHandler 中未定义的方法(如 implementation() 方法),只要 hasMethod 返回 true,就会调用到 MethodAccess 的实现者的 tryInvokeMethod 方法,其中 name 为 configuration 名称,arguments 就是 'com.android.support:appcompat-v7:28.0.0' 这个参数。 |
||||||
|
|
||||||
|
那 DependencyHandler 接口的实现者 DefaultDependencyHandler 是如何实现 MethodMixIn 这个接口的呢? |
||||||
|
|
||||||
|
```java |
||||||
|
public MethodAccess getAdditionalMethods() { |
||||||
|
return this.dynamicMethods; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
这个 dynamicMethods 类型为 DynamicAddDependencyMethods,源码如下: |
||||||
|
|
||||||
|
```java |
||||||
|
class DynamicAddDependencyMethods implements MethodAccess { |
||||||
|
private ConfigurationContainer configurationContainer; |
||||||
|
private DynamicAddDependencyMethods.DependencyAdder dependencyAdder; |
||||||
|
|
||||||
|
DynamicAddDependencyMethods(ConfigurationContainer configurationContainer, DynamicAddDependencyMethods.DependencyAdder dependencyAdder) { |
||||||
|
this.configurationContainer = configurationContainer; |
||||||
|
this.dependencyAdder = dependencyAdder; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasMethod(String name, Object... arguments) { |
||||||
|
return arguments.length != 0 && this.configurationContainer.findByName(name) != null; |
||||||
|
} |
||||||
|
|
||||||
|
public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) { |
||||||
|
if (arguments.length == 0) { |
||||||
|
return DynamicInvokeResult.notFound(); |
||||||
|
} else { |
||||||
|
Configuration configuration = (Configuration)this.configurationContainer.findByName(name); |
||||||
|
if (configuration == null) { |
||||||
|
return DynamicInvokeResult.notFound(); |
||||||
|
} else { |
||||||
|
List<?> normalizedArgs = CollectionUtils.flattenCollections(arguments); |
||||||
|
if (normalizedArgs.size() == 2 && normalizedArgs.get(1) instanceof Closure) { |
||||||
|
return DynamicInvokeResult.found(this.dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure)normalizedArgs.get(1))); |
||||||
|
} else if (normalizedArgs.size() == 1) { |
||||||
|
return DynamicInvokeResult.found(this.dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure)null)); |
||||||
|
} else { |
||||||
|
Iterator var5 = normalizedArgs.iterator(); |
||||||
|
|
||||||
|
while(var5.hasNext()) { |
||||||
|
Object arg = var5.next(); |
||||||
|
this.dependencyAdder.add(configuration, arg, (Closure)null); |
||||||
|
} |
||||||
|
|
||||||
|
return DynamicInvokeResult.found(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
interface DependencyAdder<T> { |
||||||
|
T add(Configuration var1, Object var2, Closure var3); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
注意到它是实现了 MethodAccess 这个接口的,首先看它的 hasMethod() 方法,很简单,返回 true 的条件是: |
||||||
|
|
||||||
|
* 参数长度不为零 |
||||||
|
* configuration 必须是已经定义过的 |
||||||
|
|
||||||
|
然后再看 tryInvokeMethod(),它会先通过 configurationsContainer 找到对应的 configuration,然后分如下几种情况: |
||||||
|
|
||||||
|
* 参数个数为 2,并且第 2 个参数是 Closure |
||||||
|
* 参数个数为 1 |
||||||
|
* 其他情形 |
||||||
|
|
||||||
|
不过不管哪种情形,都会先调用 dependencyAdder 的 add() 方法,而 dependencyAdder 是 DefaultDependencyHandler.DirectDependencyAdder 对象,其 add() 方法如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public Dependency add(Configuration configuration, Object dependencyNotation, @Nullable Closure configureAction) { |
||||||
|
return DefaultDependencyHandler.this.doAdd(configuration, dependencyNotation, configureAction); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
可见,其实是调用外部类 DefaultDependencyHandler 的 doAdd() 方法,在下一小节分析该方法。 |
||||||
|
|
||||||
|
#### DefaultDependencyHandler.doAdd() 方法分析 |
||||||
|
|
||||||
|
```java |
||||||
|
private Dependency doAdd(Configuration configuration, Object dependencyNotation, Closure configureClosure) { |
||||||
|
if (dependencyNotation instanceof Configuration) { |
||||||
|
Configuration other = (Configuration)dependencyNotation; |
||||||
|
if (!this.configurationContainer.contains(other)) { |
||||||
|
throw new UnsupportedOperationException("Currently you can only declare dependencies on configurations from the same project."); |
||||||
|
} else { |
||||||
|
configuration.extendsFrom(new Configuration[]{other}); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} else { |
||||||
|
Dependency dependency = this.create(dependencyNotation, configureClosure); |
||||||
|
configuration.getDependencies().add(dependency); |
||||||
|
return dependency; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
可见,这里会先判断 dependencyNotation 是否为 Configuration,如果是的话,就让当前的 configuration 继承自 other 这个 configuration,而继承的意思就是,后续所有添加到 other 的依赖,也会添加到当前这个 configuration 中。 |
||||||
|
|
||||||
|
为什么还要考虑参数中的 dependecnyNotation 是否为 Configuration 的情形呢? |
||||||
|
|
||||||
|
其实就是考虑到有诸如 implementation project(path: ':appmodule', configuration: 'configA') 这样的依赖声明。 |
||||||
|
|
||||||
|
至于依赖的创建过程,在下一节进行分析。 |
||||||
|
|
||||||
|
### 依赖创建过程分析 |
||||||
|
|
||||||
|
DefaultDependencyHandler 的 create() 方法如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public Dependency create(Object dependencyNotation, Closure configureClosure) { |
||||||
|
Dependency dependency = this.dependencyFactory.createDependency(dependencyNotation); |
||||||
|
return (Dependency)ConfigureUtil.configure(configureClosure, dependency); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
其中的 dependencyFactory 为 DefaultDependencyFactory 对象,其 createDependency() 方法如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public Dependency createDependency(Object dependencyNotation) { |
||||||
|
Dependency dependency = (Dependency)this.dependencyNotationParser.parseNotation(dependencyNotation); |
||||||
|
this.injectAttributesFactory(dependency); |
||||||
|
return dependency; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
可见,它是直接调用 dependencyNotationParser 这个解析器对于 denpendencyNotation 进行解析。 |
||||||
|
|
||||||
|
其中的 dependencyNotationParser 是实现了接口 NotationParser\<Object, Dependency> 接口的对象。 |
||||||
|
|
||||||
|
为了找出这里的 dependencyNotationParser 到底是哪个类的实例,查看 DefaultDependencyFactory 的创建,在 DependencyManagementBuildScopeServices 类中,如下: |
||||||
|
|
||||||
|
```java |
||||||
|
DependencyFactory createDependencyFactory(Instantiator instantiator, ProjectAccessListener projectAccessListener, StartParameter startParameter, ClassPathRegistry classPathRegistry, CurrentGradleInstallation currentGradleInstallation, FileLookup fileLookup, RuntimeShadedJarFactory runtimeShadedJarFactory, ImmutableAttributesFactory attributesFactory, SimpleMapInterner stringInterner) { |
||||||
|
DefaultProjectDependencyFactory factory = new DefaultProjectDependencyFactory(projectAccessListener, instantiator, startParameter.isBuildProjectDependencies()); |
||||||
|
ProjectDependencyFactory projectDependencyFactory = new ProjectDependencyFactory(factory); |
||||||
|
return new DefaultDependencyFactory(DependencyNotationParser.parser(instantiator, factory, classPathRegistry, fileLookup, runtimeShadedJarFactory, currentGradleInstallation, stringInterner), DependencyConstraintNotationParser.parser(instantiator, stringInterner), (new ClientModuleNotationParserFactory(instantiator, stringInterner)).create(), projectDependencyFactory, attributesFactory); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
可见,它是通过 DependencyNotationParser.parser() 方法创建的,该方法如下: |
||||||
|
|
||||||
|
```java |
||||||
|
public static NotationParser<Object, Dependency> parser(Instantiator instantiator, DefaultProjectDependencyFactory dependencyFactory, ClassPathRegistry classPathRegistry, FileLookup fileLookup, RuntimeShadedJarFactory runtimeShadedJarFactory, CurrentGradleInstallation currentGradleInstallation, Interner<String> stringInterner) { |
||||||
|
return NotationParserBuilder.toType(Dependency.class).fromCharSequence(new DependencyStringNotationConverter(instantiator, DefaultExternalModuleDependency.class, stringInterner)).converter(new DependencyMapNotationConverter(instantiator, DefaultExternalModuleDependency.class)).fromType(FileCollection.class, new DependencyFilesNotationConverter(instantiator)).fromType(Project.class, new DependencyProjectNotationConverter(dependencyFactory)).fromType(ClassPathNotation.class, new DependencyClassPathNotationConverter(instantiator, classPathRegistry, fileLookup.getFileResolver(), runtimeShadedJarFactory, currentGradleInstallation)).invalidNotationMessage("Comprehensive documentation on dependency notations is available in DSL reference for DependencyHandler type.").toComposite(); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
这个方法其实很好理解,它其实是创建了多个实现了接口 NotationConverter 的对象,然后将这些转换器都添加在一起,构成一个综合的转换器。 |
||||||
|
|
||||||
|
其中,DependencyStringNotationConvert 负责将字符串类型的 notation 转换为 DefaultExternalModuleDependency,也就是对应 implementation 'com.android.support:appcompat-v7:25.1.0' 这样的声明; |
||||||
|
|
||||||
|
DependencyFilesNotationConverter 将 FileCollection 转换为 SelfResolvingDependency,也就是对应的 implementation fileTree(dir: 'libs', include:['*.jar']) 这样的声明; |
||||||
|
|
||||||
|
DependencyProjectNotationConverter 将 Project 转换为 ProjectDependency,对应 implementation project(":appmodule") 这样的情形; |
||||||
|
|
||||||
|
DependencyClasspathNotationConvert 将 ClasspathNotation 转换为 SelfResolvingDependency; |
||||||
|
|
||||||
|
到这里,就知道类似 implementation 'com.android.support:appcompat-v7:28.0.0' 和 implementation project 这样的声明,其实是被不同的转换器,转换成了 SelfResolvingDependency 或者 ProjectDependency。 |
||||||
|
|
||||||
|
这里可以看出,除了 project 依赖之外,其他都转换成 SelfResolvingDependency,所谓的 SelfResolvingDependency 其实是可以自解析的依赖,独立于 repository。 |
||||||
|
|
||||||
|
ProjectDependency 则不然,它是依赖于 repository 的,下面就分析 ProjectDependency 的独特之处。 |
||||||
|
|
Loading…
Reference in new issue