gradle源碼分析之implementation依賴

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());
}

dependenciesproject下的方法, 實際返回DefaultDependencyHandler.

即執(zhí)行DefaultDependencyHandlerimplementation方法。

但是底下并沒有這個方法收捣,

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是沒有projectconfiguration:

于是進入DefaultProjectproject方法

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;
        }
    }
}

問題

為什么能進入DefaultProjectproject方法? 因為回到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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饲齐,一起剝皮案震驚了整個濱河市钉凌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捂人,老刑警劉巖御雕,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滥搭,居然都是意外死亡酸纲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門瑟匆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闽坡,“玉大人,你說我怎么就攤上這事愁溜〖残幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵冕象,是天一觀的道長代承。 經(jīng)常有香客問我,道長渐扮,這世上最難降的妖魔是什么论悴? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮墓律,結(jié)果婚禮上意荤,老公的妹妹穿的比我還像新娘。我一直安慰自己只锻,他們只是感情好玖像,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般捐寥。 火紅的嫁衣襯著肌膚如雪笤昨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天握恳,我揣著相機與錄音瞒窒,去河邊找鬼。 笑死乡洼,一個胖子當著我的面吹牛崇裁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播束昵,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拔稳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锹雏?” 一聲冷哼從身側(cè)響起巴比,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎礁遵,沒想到半個月后轻绞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡佣耐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年政勃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兼砖。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奸远,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掖鱼,到底是詐尸還是另有隱情然走,我是刑警寧澤援制,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布戏挡,位于F島的核電站,受9級特大地震影響晨仑,放射性物質(zhì)發(fā)生泄漏褐墅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一洪己、第九天 我趴在偏房一處隱蔽的房頂上張望妥凳。 院中可真熱鬧,春花似錦答捕、人聲如沸逝钥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艘款。三九已至持际,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哗咆,已是汗流浹背蜘欲。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晌柬,地道東北人姥份。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像年碘,于是被迫代替她去往敵國和親澈歉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353