Groovy
dependencies {
implementation project(':sdk')
}
groovy會做兩步:
- 解析project
- 解析implementation
我們先看第二步
解析implementation
Project.java
/**
* <p>Configures the dependencies for this project.
*
* <p>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.
*
* <h3>Examples:</h3>
* 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
.
即執(zhí)行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);
}
動態(tài)語言常見的methodMissing
功能扬霜,這里在tryInvokeMethod
嘗試解析方法與參數(shù)。
class DynamicAddDependencyMethods implements MethodAccess {
//name = "implementation" argument: project(sdk)
public DynamicInvokeResult tryInvokeMethod(String name, Object... arguments) {
//找是否有對應(yīng)的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 轉(zhuǎn)換為 ProjectDependency蜡励,對應(yīng) 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<String, *>): Dependency =
delegate.project(notation)
最后走到DependencyHandler.project(map)
方法 -> (delegate)
public Dependency project(Map<String, ?> 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 找到相應(yīng)的 Project,然后通過 factory 創(chuàng)建 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
咋實現(xiàn)的顷蟆,還沒看懂
參考資料
https://henleylee.github.io/posts/2019/5fe63be9.html#toc-heading-5
http://www.reibang.com/p/0e04186a6aca