您好,登錄后才能下訂單哦!
由于我們可以把Gradle源代碼里面的launcher包丟到gradle libs下面去編譯應(yīng)用程序,所以我們可以用Gradle源代碼里面的launcher源代碼進(jìn)行分析。
至于Gradle源代碼和gradle bin的關(guān)系,可以參考上一篇帖子:
Gradle自身源代碼編譯
這個(gè)很重要,弄清楚雞和蛋的問題,下面正式開始。
一. GradleMain
文件路徑:
subprojects\launcher\src\main\java\org\gradle\launcher\GradleMain.java
public static void main(String[] args) throws Exception { new ProcessBootstrap().run("org.gradle.launcher.Main", args); } public class ProcessBootstrap { /** * Sets up the ClassLoader structure for the given class, creates an instance and invokes {@link EntryPoint#run(String[])} on it. */ public void run(String mainClassName, String[] args) { try { runNoExit(mainClassName, args); System.exit(0); } catch (Throwable throwable) { throwable.printStackTrace(); System.exit(1); } } private void runNoExit(String mainClassName, String[] args) throws Exception { ClassPathRegistry classPathRegistry = new DefaultClassPathRegistry(new DefaultClassPathProvider(new DefaultModuleRegistry(CurrentGradleInstallation.get()))); ClassLoaderFactory classLoaderFactory = new DefaultClassLoaderFactory(); ClassPath antClasspath = classPathRegistry.getClassPath("ANT"); ClassPath runtimeClasspath = classPathRegistry.getClassPath("GRADLE_RUNTIME"); ClassLoader antClassLoader = classLoaderFactory.createIsolatedClassLoader(antClasspath); ClassLoader runtimeClassLoader = new VisitableURLClassLoader(antClassLoader, runtimeClasspath); ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(runtimeClassLoader); try { Class<?> mainClass = runtimeClassLoader.loadClass(mainClassName); Object entryPoint = mainClass.newInstance(); Method mainMethod = mainClass.getMethod("run", String[].class); mainMethod.invoke(entryPoint, new Object[]{args}); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); ClassLoaderUtils.tryClose(runtimeClassLoader); ClassLoaderUtils.tryClose(antClassLoader); } } }
這行代碼其實(shí)就是啟動(dòng)org.gradle.launcher.main.run方法
二. org.gradle.launcher.main
其實(shí)走的是doAction方法,因?yàn)閞un方法是它的父類EntryPoint里面:
public abstract class EntryPoint { /** * Unless the createCompleter() method is overridden, the JVM will exit before returning from this method. */ public void run(String[] args) { RecordingExecutionListener listener = new RecordingExecutionListener(); try { doAction(args, listener); } catch (Throwable e) { createErrorHandler().execute(e); listener.onFailure(e); } Throwable failure = listener.getFailure(); ExecutionCompleter completer = createCompleter(); if (failure == null) { completer.complete(); } else { completer.completeWithFailure(failure); } }
所以看doAction方法:
public class Main extends EntryPoint { public static void main(String[] args) { new Main().run(args); } protected void doAction(String[] args, ExecutionListener listener) { createActionFactory().convert(Arrays.asList(args)).execute(listener); } CommandLineActionFactory createActionFactory() { return new CommandLineActionFactory(); } } //createActionFactory.java public Action<ExecutionListener> convert(List<String> args) { ServiceRegistry loggingServices = createLoggingServices(); LoggingConfiguration loggingConfiguration = new DefaultLoggingConfiguration(); return new WithLogging(loggingServices, args, loggingConfiguration, new ExceptionReportingAction( new JavaRuntimeValidationAction( new ParseAndBuildAction(loggingServices, args)), new BuildExceptionReporter(loggingServices.get(StyledTextOutputFactory.class), loggingConfiguration, clientMetaData()))); }
從convert方法可以看到返回的是WithLogging對象,但是它里面又包了好幾層。
其實(shí)它們都是實(shí)現(xiàn)了Action<ExecutionListener>接口:
private static class WithLogging implements Action<ExecutionListener> {} public class ExceptionReportingAction implements Action<ExecutionListener> {} public class JavaRuntimeValidationAction implements Action<ExecutionListener> {} private class ParseAndBuildAction implements Action<ExecutionListener> {}
這是裝飾者模式。
關(guān)于裝飾者模式大家可以百度下,大概有兩點(diǎn):
類實(shí)現(xiàn)同一個(gè)接口
互相包裝
打個(gè)比方,有這么一個(gè)場景:
咖啡店咖啡賣3塊一杯,于是我們可以這樣設(shè)計(jì):
interface Drink{ int price(); } class Coffee implements Drink{ int price(){return 3;} }
哪天需要開發(fā)了新產(chǎn)品,嗯,加糖的咖啡,需要賣5塊,那可以設(shè)計(jì)如下:
class SugarCoffee implements Drink{ Drink mDrink; SugarCoffee(Drink drink){ mDrink = drink; } int price(){ return 2 + mDrink.price(); } } main(){ SugarCoffee sc = new SugarCoffee(new Coffee()); int price = sc.price(); }
嗯,大概就是這個(gè)意思。。Gradle這里也用了同樣的模式。
最后,我們看最關(guān)鍵的ParseAndBuildAction.execute(xxx)方法
三. ParseAndBuildAction.execute(xxx)
protected void createActionFactories(ServiceRegistry loggingServices, Collection<CommandLineAction> actions) { actions.add(new GuiActionsFactory()); actions.add(new BuildActionsFactory(loggingServices, new ParametersConverter(), new CachingJvmVersionDetector(new DefaultJvmVersionDetector(new DefaultExecActionFactory(new IdentityFileResolver()))))); } public void execute(ExecutionListener executionListener) { System.out.println("ParseAndBuildAction execute"); List<CommandLineAction> actions = new ArrayList<CommandLineAction>(); //添加BuiltInActions actions.add(new BuiltInActions()); //添加GuiActionsFactory和BuildActionsFactory createActionFactories(loggingServices, actions); CommandLineParser parser = new CommandLineParser(); for (CommandLineAction action : actions) { action.configureCommandLineParser(parser); } Action<? super ExecutionListener> action; try { ParsedCommandLine commandLine = parser.parse(args); action = createAction(actions, parser, commandLine); Exception exx = new Exception("Sandt ParseAndBuildAction execute.."); exx.printStackTrace(); System.out.println("action: " + action); } catch (CommandLineArgumentException e) { action = new CommandLineParseFailureAction(parser, e); } action.execute(executionListener); } private Action<? super ExecutionListener> createAction(Iterable<CommandLineAction> factories, CommandLineParser parser, ParsedCommandLine commandLine) { for (CommandLineAction factory : factories) { Runnable action = factory.createAction(parser, commandLine); if (action != null) { return Actions.toAction(action); } } throw new UnsupportedOperationException("No action factory for specified command-line arguments."); }
execute里面首先會(huì)添加3個(gè)ActionFactory
BuildInActions表示gradle -help和gradle -version 命令
GuiActionsFactory表示gradle -gui命令
BuildActionsFactory表示其他編譯命令,比如gradle assemble,下面我們主要分析這種。
調(diào)用createAction方法,其實(shí)就是挨個(gè)調(diào)用上面3個(gè)ActionsFacory的createAction方法。那我們主要看BuildActionsFactory。
四. BuildActionsFactory.createAction
public Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) { Parameters parameters = parametersConverter.convert(commandLine, new Parameters()); parameters.getDaemonParameters().applyDefaultsFor(jvmVersionDetector.getJavaVersion(parameters.getDaemonParameters().getEffectiveJvm())); if (parameters.getDaemonParameters().isStop()) { System.out.println("createAction 1"); return stopAllDaemons(parameters.getDaemonParameters(), loggingServices); } if (parameters.getDaemonParameters().isStatus()) { System.out.println("createAction 2"); return showDaemonStatus(parameters.getDaemonParameters(), loggingServices); } if (parameters.getDaemonParameters().isForeground()) { System.out.println("createAction 3"); DaemonParameters daemonParameters = parameters.getDaemonParameters(); ForegroundDaemonConfiguration conf = new ForegroundDaemonConfiguration( UUID.randomUUID().toString(), daemonParameters.getBaseDir(), daemonParameters.getIdleTimeout(), daemonParameters.getPeriodicCheckInterval()); return new ForegroundDaemonAction(loggingServices, conf); } if (parameters.getDaemonParameters().isEnabled()) { System.out.println("createAction 4"); return runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices); // return runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices); } if (canUseCurrentProcess(parameters.getDaemonParameters())) { System.out.println("createAction 5"); return runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices); } System.out.println("createAction 6"); return runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices); }
編譯種類主要分為兩種:
在本進(jìn)程編譯
在守護(hù)進(jìn)程編譯
選擇邏輯是:
如果有守護(hù)進(jìn)程在運(yùn)行,那么連接守護(hù)進(jìn)程然后在守護(hù)進(jìn)程編譯。
如果可以在當(dāng)前進(jìn)程編譯,那么就在當(dāng)前進(jìn)程編譯。
如果都不滿足,那就啟動(dòng)守護(hù)進(jìn)程,然后進(jìn)行編譯。
判斷是否可以在當(dāng)前進(jìn)程編譯的代碼如下:
subprojects\launcher\src\main\java\org\gradle\launcher\daemon\configuration\BuildProcess.java
/** * Attempts to configure the current process to run with the required build parameters. * @return True if the current process could be configured, false otherwise. */ public boolean configureForBuild(DaemonParameters requiredBuildParameters) { boolean javaHomeMatch = getJvm().equals(requiredBuildParameters.getEffectiveJvm()); final JvmOptions jvmOptions = new JvmOptions(new IdentityFileResolver()); jvmOptions.systemProperties(getJvmOptions().getImmutableSystemProperties()); List<String> currentImmutables = jvmOptions.getAllImmutableJvmArgs(); List<String> requiredImmutables = requiredBuildParameters.getEffectiveSingleUseJvmArgs(); requiredImmutables.removeAll(DaemonParameters.DEFAULT_JVM_ARGS); boolean noImmutableJvmArgsRequired = requiredImmutables.equals(currentImmutables); System.out.println("javaHomeMatch: " + javaHomeMatch + " noImmutableJvmArgsRequired: " + noImmutableJvmArgsRequired); System.out.println("getJvm(): " + getJvm() + " requiredBuildParameters.getEffectiveJvm(): " + requiredBuildParameters.getEffectiveJvm()); for (String re : requiredImmutables) { System.out.println("requiredImmutable: " + re); } for (String re : currentImmutables) { System.out.println("currentImmutable: " + re); } if (javaHomeMatch && noImmutableJvmArgsRequired) { // Set the system properties and use this process Properties properties = new Properties(); properties.putAll(requiredBuildParameters.getEffectiveSystemProperties()); System.setProperties(properties); return true; } return false; }
打印日志:
javaHomeMatch: true noImmutableJvmArgsRequired: false getJvm(): 1.8.0_25 (Oracle Corporation 25.25-b02) requiredBuildParameters.getEffectiveJvm(): 1.8.0_25 (Oracle Corporation 25.25-b02) requiredImmutable: -Xmx1536m requiredImmutable: -Dfile.encoding=GBK requiredImmutable: -Duser.country=CN requiredImmutable: -Duser.language=zh requiredImmutable: -Duser.variant currentImmutable: -Dfile.encoding=GBK currentImmutable: -Duser.country=CN currentImmutable: -Duser.language=zh currentImmutable: -Duser.variant
從日志看環(huán)境有點(diǎn)不一樣,所以我的環(huán)境會(huì)采用守護(hù)進(jìn)程的方法。 不過為了調(diào)試,我可以修改代碼強(qiáng)制采用本進(jìn)程編譯的方式。
這兩種編譯流程不盡相同,下一篇文章會(huì)先講在本進(jìn)程編譯的流程。然后再講啟動(dòng)守護(hù)進(jìn)程進(jìn)程編譯流程。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。