gradle-1启动篇

本文详细剖析了gradle-6.9.1的启动过程,从gradlew.bat入口到GradleWrapperMain.main方法,再到wrapper模块的下载与解压,以及GradleMain.main的执行。在启动过程中,重点解析了Gradle服务注册与查找机制,如何通过DefaultServiceRegistry创建和装饰服务。文章最后提到gradle的五个执行阶段,并预告后续将深入探讨这些阶段。

grade-1 启动流程(v6.9.1)

引子

做为Android开发,不仅需要对Apk构建流程熟悉外,还要知道gradle内部实现,通常说的gradle的生命周期你知道分为哪几个阶段吗?在不同生命周期你知道gradle到底做了什么吗?
本篇开始研究下gradle源码内部基本实现吧,你能从中找到答案,此处以6.9.1版本为分析

先看入口吧,gradlew.bat文件,里面核心代码

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

前三个为空,最终调用的是GradleWrapperMain.main方法

准备

准备gradle源码

git clone https://github.com/gradle/gradle
gcb feature_v6.9.1 v6.9.1

修改com.gradle.enterprise:test-distribution-gradle-plugin:1.1.2-rc-1调整为com.gradle.enterprise:test-distribution-gradle-plugin:1.1.2同步即可

wrapper模块

image-20211217095118494

入口如下

// org.gradle.wrapper.GradleWrapperMain.java
public static void main(String[] args) throws Exception {
  			
  			// gradle-wrapper.jar
        File wrapperJar = wrapperJar();
        // load gradle-wrapper.properties file
        File propertiesFile = wrapperProperties(wrapperJar);
        File rootDir = rootDir(wrapperJar);

        CommandLineParser parser = new CommandLineParser();
        parser.allowUnknownOptions();
        parser.option(GRADLE_USER_HOME_OPTION, GRADLE_USER_HOME_DETAILED_OPTION).hasArgument();
        parser.option(GRADLE_QUIET_OPTION, GRADLE_QUIET_DETAILED_OPTION);

        SystemPropertiesCommandLineConverter converter = new SystemPropertiesCommandLineConverter();
        converter.configure(parser);

        ParsedCommandLine options = parser.parse(args);

        Properties systemProperties = System.getProperties();
        systemProperties.putAll(converter.convert(options, new HashMap<String, String>()));
				
		// gradle home 目录:~/.gradle
        File gradleUserHome = gradleUserHome(options);

        addSystemProperties(gradleUserHome, rootDir);

        Logger logger = logger(options);
				
		// 构建一个wrapper执行器,调用execute;
		// 1. 执行安装(如果本地没有安装
        WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
        wrapperExecutor.execute(
                args,
                new Install(logger, new Download(logger, "gradlew", UNKNOWN_VERSION), new PathAssembler(gradleUserHome)),
                new BootstrapMainStarter());
    }

// org.gradle.wrapper.WrapperExecutor.java
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {				
  			// 
        File gradleHome = install.createDist(config);
        bootstrapMainStarter.start(args, gradleHome);
    }

此处会调用wrapperExecutor.execute方法;主要做了2件事件

  1. createDist -> 如果没有gradle,下载grade文件(Grade-wrapper.properties文件中distributionUrl对应的文件)并解压;否则直接返回gradlehome文件
  2. start -> 调用org.gradle.launcher.GradleMain.main方法(反射)

1. 下载,解压gradle

先看下Grade-wrapper.properties文件格式如下

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

里面包含了需要下载gradle包的链接地址,WrapperConfiguration配置里面就包含了这些元信息

public File createDist(final WrapperConfiguration configuration) throws Exception {
        final URI distributionUrl = configuration.getDistribution();
        final String distributionSha256Sum = configuration.getDistributionSha256Sum();

        final PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution(configuration);
        final File distDir = localDistribution.getDistributionDir();
        final File localZipFile = localDistribution.getZipFile();

        return exclusiveFileAccessManager.access(localZipFile, new Callable<File>() {
            public File call() throws Exception {
                final File markerFile = new File(localZipFile.getParentFile(), localZipFile.getName() + ".ok");
              	// 如果本地目录存在&存在.ok文件;
                if (distDir.isDirectory() && markerFile.isFile()) {
                    InstallCheck installCheck = verifyDistributionRoot(distDir, distDir.getAbsolutePath());
                    if (installCheck.isVerified()) {
                      	// 验证通过,直接返回gradlehome
                        return installCheck.gradleHome;
                    }
                    // Distribution is invalid. Try to reinstall.
                    System.err.println(installCheck.failureMessage);
                    markerFile.delete();
                }

                boolean needsDownload = !localZipFile.isFile();
                URI safeDistributionUrl = Download.safeUri(distributionUrl);

                if (needsDownload) {
                    File tmpZipFile = new File(localZipFile.getParentFile(), localZipFile.getName() + ".part");
                    tmpZipFile.delete();
                    logger.log("Downloading " + safeDistributionUrl);
                    download.download(distributionUrl, tmpZipFile);
                    tmpZipFile.renameTo(localZipFile);
                }

                List<File> topLevelDirs = listDirs(distDir);
                for (File dir : topLevelDirs) {
                    logger.log("Deleting directory " + dir.getAbsolutePath());
                    deleteDir(dir);
                }

                verifyDownloadChecksum(configuration.getDistribution().toString(), localZipFile, distributionSha256Sum);

                try {
                    unzip(localZipFile, distDir);
                } catch (IOException e) {
                    logger.log("Could not unzip " + localZipFile.getAbsolutePath() + " to " + distDir.getAbsolutePath() + ".");
                    logger.log("Reason: " + e.getMessage());
                    throw e;
                }

                InstallCheck installCheck = verifyDistributionRoot(distDir, safeDistributionUrl.toString());
                if (installCheck.isVerified()) {
                    setExecutablePermissions(installCheck.gradleHome);
                    markerFile.createNewFile();
                    return installCheck.gradleHome;
                }
                // Distribution couldn't be installed.
                throw new RuntimeException(installCheck.failureMessage);
            }
        });
    }

2. 启动

image-20211217095544536

GradleMain.main

在这里插入图片描述

GradleMain.main -> ProcessBootstrap.run 最终来到了org.gradle.launcher.Main.run方法 -> DefaultCommandLineActionFactory.convert(Arrays.asList(args)).execute(listener) ==> WithLogging.execute ==>

image-20220124150835065

做了一层装饰器,层层调用最终还是执行了action 也即是ParseAndBuildAction.execute

在这里插入图片描述

ParseAndBuildAction中最终会调用BuildActionsFactory.createAction ==> runBuildInProcess

private Runnable runBuildInProcess(StartParameterInternal startParameter, DaemonParameters daemonParameters) {
			// DefaultServiceRegistry
  		ServiceRegistry globalServices = ServiceRegistryBuilder.builder()
            .displayName("Global services")
            .parent(loggingServices)
            .parent(NativeServices.getInstance())
            .provider(new GlobalScopeServices(startParameter.isContinuous()))
            .build();

        // Force the user home services to be stopped first, the dependencies between the user home services and the global services are not preserved currently
        return runBuildAndCloseServices(startParameter, daemonParameters, globalServices.get(BuildExecuter.class), globalServices, globalServices.get(GradleUserHomeScopeServiceRegistry.class));
    }

此处的globalServices其实是DefaultServiceRegistry类型,可以理解为全局服务,别人可以向他注册服务
在这里插入图片描述
那么DefaultServiceRegistry是如何做到自动提供多项服务呢?先来看看DefaultServiceRegistry的构造器比较有意思
在这里插入图片描述
重点是findProviderMethods方法,这里传的参数其实是他本身;
该方法总结下,其实是扫描自身类的三类方法
在这里插入图片描述

  1. decorator方法:create_xxxxx或decorate_xxxx (返回值不能为void)
  2. factory方法:非静态方法 create_xxxx (返回值不能为void)
  3. configure方法:configure_xxx
    解析这些方法,生成一个RelevantMethods对象,这个对象被放到缓存中;后续调用相关服务直接从这里取就行了

我看仔细看下DefaultServiceRegistry类其实并没有我们所说的那些方法,猜测应该是放到对应的子类去实现了,下面的类都是其子类,每个类对应一个服务
在这里插入图片描述

private void findProviderMethods(Object target) {
        Class<?> type = target.getClass();
  
  			//1.  方法解析
        RelevantMethods methods = RelevantMethods.getMethods(type);
  
  			// 2. 对方法进行分类处理,转化为相关的方法服务,编译外部调用
        for (ServiceMethod method : methods.decorators) {
            if (parentServices == null) {
                throw new ServiceLookupException(String.format("Cannot use decorator method %s.%s() when no parent registry is provided.", type.getSimpleName(), method.getName()));
            }
            ownServices.add(new FactoryMethodService(this, target, method));
        }
        for (ServiceMethod method : methods.factories) {
            ownServices.add(new FactoryMethodService(this, target, method));
        }
  
  			// 3. 针对 config配置,则直接反射调用
        for (ServiceMethod method : methods.configurers) {
            applyConfigureMethod(method, target);
        }
    }
private void applyConfigureMethod(ServiceMethod method, Object target) {
        Object[] params = new Object[method.getParameterTypes().length];
        for (int i = 0; i < method.getParameterTypes().length; i++) {
            Type paramType = method.getParameterTypes()[i];
            if (paramType.equals(ServiceRegistration.class)) {
                params[i] = newRegistration();
            } else {
                Service paramProvider = find(paramType, allServices);
                if (paramProvider == null) {
                    throw new ServiceLookupException(String.format("Cannot configure services using %s.%s() as required service of type %s is not available.",
                        method.getOwner().getSimpleName(),
                        method.getName(),
                        format(paramType)));
                }
                params[i] = paramProvider.get();
            }
        }
        try {
            method.invoke(target, params);
        } catch (Exception e) {
            throw new ServiceLookupException(String.format("Could not configure services using %s.%s().",
                method.getOwner().getSimpleName(),
                method.getName()), e);
        }
    }

回头再看ServiceRegistryBuilder

 public ServiceRegistry build() {
        DefaultServiceRegistry registry = new DefaultServiceRegistry(displayName, parents.toArray(new ServiceRegistry[0]));
        for (Object provider : providers) {
            registry.addProvider(provider);
        }
        return registry;
    }
	
		// DefaultServiceRegistry.java
		/**
     * Adds a service provider bean to this registry. This provider may define factory and decorator methods.
     */
    public DefaultServiceRegistry addProvider(Object provider) {
        assertMutable();
        findProviderMethods(provider);
        return this;
    }

可以看到此处又再次调用了findProviderMethods(provider);也就是对GlobalScopeServices类做解析处理了,GlobalScopeServices类中包含了需要相关的服务方法,这样globalServices就正式成为名副其实的全局服务了
在这里插入图片描述
后面中间流程有点绕,可以忽略,最终来到了DefaultGradleLauncher.executeTasks

public GradleInternal executeTasks() {
        doBuildStages(Stage.RunTasks);
        return gradle;
}

至此进入了gradle五个Stage流程中,很熟悉吧,就是传说中gradle的几个阶段,后续会对这几个阶段进行逐篇介绍

private enum Stage {
        LoadSettings,
        Configure,
        TaskGraph,
        RunTasks() {
            @Override
            String getDisplayName() {
                return "Build";
            }
        },
  			Finished;

        String getDisplayName() {
            return name();
        }
    }
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值