Groovy
dependencies {
implementation project(':sdk')
}
groovy会做两步:
- 解析project
- 解析implementation
我们先看第二步
解析implementation
Project.java
/**
* Configures the dependencies for this project.
*
*
This method executes the given closure against the {@link DependencyHandler} for this project. The {@link
* DependencyHandler} is passed to the closure as the closure's delegate.
*
*
Examples:
* See docs for {@link DependencyHandler}
*
* @param configureClosure the closure to use to configure the dependencies.
*/
void dependencies(Closure configureClosure);
public void dependencies(Closure configureClosure) {
ConfigureUtil.configure(configureClosure, this.getDependencies());
}
dependencies
是project下的方法
, 实际返回DefaultDependencyHandler
.
即执行DefaultDependencyHandler
的implementation
方法。
但是底下并没有这个方法,
MethodMissing
MethodMixIn
public interface MethodMixIn {
MethodAccess getAdditionalMethods();
}
this.dynamicMethods = new DynamicAddDependencyMethods(configurationContainer, new DefaultDependencyHandler.DirectDependencyAdder());
MethodAccess
public interface MethodAccess {
boolean hasMethod(String var1, Object... var2);
DynamicInvokeResult tryInvokeMethod(String var1, Object... var2);
}
动态语言常见的methodMissing
功能,这里在tryInvokeMethod
尝试解析方法与参数。
class DynamicAddDependencyMethods implements MethodAccess {
//name = "implementation" argument: project(sdk)
public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) {
//找是否有对应的configurationName
Configuration configuration = (Configuration)this.configurationContainer.findByName(name);
return DynamicInvokeResult.found(this.dependencyAdder.add(configuration, normalizedArgs.get(0), (Closure)null));
}
}
/**
dependencyNotation: project(:xxx)
*/
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;
}
}
public Dependency create(Object dependencyNotation, Closure configureClosure) {
Dependency dependency = this.dependencyFactory.createDependency(dependencyNotation);
return (Dependency)ConfigureUtil.configure(configureClosure, dependency);
}
//DependencyProjectNotationConverter
public Dependency createDependency(Object dependencyNotation) {
Dependency dependency = (Dependency)this.dependencyNotationParser.parseNotation(dependencyNotation);
this.injectServices(dependency);
return dependency; //DefaultProjectDependency
}
DependencyProjectNotationConverter 将 Project 转换为 ProjectDependency,对应 implementation project(":applemodule") 这样的情形
所以主要就两步:
1. Dependency dependency = this.create(dependencyNotation, configureClosure);
2. configuration.getDependencies().add(dependency);
解析project
一样进入tryInvokeMethod
,但是:
Configuration configuration = (Configuration)this.configurationContainer.findByName(name);
DynamicAddDependencyMethods
是没有project
的configuration
:
于是进入DefaultProject
的project
方法
public class DefaultProject {
public ProjectInternal project(String path) {
ProjectInternal project = this.findProject(path);
if (project == null) {
throw new UnknownProjectException(String.format("Project with path '%s' could not be found in %s.", path, this));
} else {
return project;
}
}
}
问题
为什么能进入DefaultProject
的project
方法? 因为回到parent去解析?
ktx
dependencies {
implementation(project(":sdkapi"))
}
ProjectExtensions.kt
fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) =
DependencyHandlerScope.of(dependencies).configuration()
companion object {
fun of(dependencies: DependencyHandler): DependencyHandlerScope =
DependencyHandlerScope(dependencies)
}
解析project
DependencyHandlerExtensions.kt
fun DependencyHandler.project(
path: String,
configuration: String? = null
): ProjectDependency =
uncheckedCast(
project(
if (configuration != null) mapOf("path" to path, "configuration" to configuration)
else mapOf("path" to path)))
override fun project(notation: Map): Dependency =
delegate.project(notation)
最后走到DependencyHandler.project(map)
方法 -> (delegate)
public Dependency project(Map notation) {
return this.dependencyFactory.createProjectDependencyFromMap(this.projectFinder, notation);
}
怪不得一直不知道这个方法是用来干啥的
project(map)
public ProjectDependency createFromMap(ProjectFinder projectFinder, Map extends String, ?> map) {
return (ProjectDependency)NotationParserBuilder.toType(ProjectDependency.class).converter(new ProjectDependencyFactory.ProjectDependencyMapNotationConverter(projectFinder, this.factory)).toComposite().parseNotation(map);
}
最后其实就是进入:
DefaultProjectDependencyFactory
public ProjectDependency create(ProjectInternal project, String configuration) {
DefaultProjectDependency projectDependency = (DefaultProjectDependency)this.instantiator.newInstance(DefaultProjectDependency.class, new Object[]{project, configuration, this.projectAccessListener, this.buildProjectDependencies});
projectDependency.setAttributesFactory(this.attributesFactory);
projectDependency.setCapabilityNotationParser(this.capabilityNotationParser);
return projectDependency;
}
先通过 projectFinder 找到相应的 Project,然后通过 factory 创建 ProjectDependency
解析implementation
val implementation by configurations
operator fun Configuration.invoke(dependencyNotation: Any): Dependency? =
add(name, dependencyNotation)
DefaultDependencyHandler.java
public Dependency add(String configurationName, Object dependencyNotation) {
return this.add(configurationName, dependencyNotation, (Closure)null);
}
问题
val implementation by configurations
咋实现的,还没看懂
参考资料
https://henleylee.github.io/posts/2019/5fe63be9.html#toc-heading-5
https://www.jianshu.com/p/0e04186a6aca