20. Gradle编译其他应用代码流程(七) - 守护进程编译

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

上一篇博客

18. Gradle编译其他应用代码流程(六) - 执行Task过程


一. 守护进程的作用

守护进程就是一个用来构建的其他进程。

从前几篇文章我们知道gradle编译的时候会加载各种所需要的Jar,加载这些Jar是需要时间的。

如果我们之前有守护进程编译过其他程序,而这个进程没有被kill掉,那么是可以重用这个守护进程的。


二. 选择守护进程编译

选择守护进程编译的策略是

  1. 如果守护进程存在,那么就使用守护进程编译。

  2. 否则,如果可以在当前进程编译,那么就在当前进程编译。

  3. 否则,启动新的守护进程来编译。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class  BuildActionsFactory  implements  CommandLineAction {
     
     public  Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {
         ...
         
         if  (parameters.getDaemonParameters().isEnabled()) {
             return  runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
         }
         if  (canUseCurrentProcess(parameters.getDaemonParameters())) {
             return  runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
         }
 
         return  runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
     }
}


三. 启动守护进程的入口


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public  class  DefaultDaemonStarter  implements  DaemonStarter {
     ....
 
     public  DaemonStartupInfo startDaemon() {
         String daemonUid = UUID.randomUUID().toString();
 
         GradleInstallation gradleInstallation = CurrentGradleInstallation.get();
         ModuleRegistry registry =  new  DefaultModuleRegistry(gradleInstallation);
         ClassPath classpath;
         List<File> searchClassPath;
         if  (gradleInstallation ==  null ) {
             // When not running from a Gradle distro, need runtime impl for launcher plus the search path to look for other modules
             classpath =  new  DefaultClassPath();
             for  (Module module : registry.getModule( "gradle-launcher" ).getAllRequiredModules()) {
                 classpath = classpath.plus(module.getClasspath());
             }
             searchClassPath = registry.getAdditionalClassPath().getAsFiles();
         else  {
             // When running from a Gradle distro, only need launcher jar. The daemon can find everything from there.
             classpath = registry.getModule( "gradle-launcher" ).getImplementationClasspath();
             searchClassPath = Collections.emptyList();
         }
         if  (classpath.isEmpty()) {
             throw  new  IllegalStateException( "Unable to construct a bootstrap classpath when starting the daemon" );
         }
 
         versionValidator.validate(daemonParameters);
 
         List<String> daemonArgs =  new  ArrayList<String>();
         daemonArgs.add(daemonParameters.getEffectiveJvm().getJavaExecutable().getAbsolutePath());
 
         List<String> daemonOpts = daemonParameters.getEffectiveJvmArgs();
         daemonArgs.addAll(daemonOpts);
         daemonArgs.add( "-cp" );
         daemonArgs.add(CollectionUtils.join(File.pathSeparator, classpath.getAsFiles()));
 
         if  (Boolean.getBoolean( "org.gradle.daemon.debug" )) {
             daemonArgs.add( "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" );
         }
         
         daemonArgs.add(GradleDaemon. class .getName());
         // Version isn't used, except by a human looking at the output of jps.
         daemonArgs.add(GradleVersion.current().getVersion());
 
         // Serialize configuration to daemon via the process' stdin
         ByteArrayOutputStream serializedConfig =  new  ByteArrayOutputStream();
         FlushableEncoder encoder =  new  KryoBackedEncoder( new  EncodedStream.EncodedOutput(serializedConfig));
         try  {
             encoder.writeString(daemonParameters.getGradleUserHomeDir().getAbsolutePath());
             encoder.writeString(daemonDir.getBaseDir().getAbsolutePath());
             encoder.writeSmallInt(daemonParameters.getIdleTimeout());
             encoder.writeSmallInt(daemonParameters.getPeriodicCheckInterval());
             encoder.writeString(daemonUid);
             encoder.writeSmallInt(daemonOpts.size());
             for  (String daemonOpt : daemonOpts) {
                 encoder.writeString(daemonOpt);
             }
             encoder.writeSmallInt(searchClassPath.size());
             for  (File file : searchClassPath) {
                 encoder.writeString(file.getAbsolutePath());
             }
             encoder.flush();
         catch  (IOException e) {
             throw  new  UncheckedIOException(e);
         }
         ByteArrayInputStream stdInput =  new  ByteArrayInputStream(serializedConfig.toByteArray());
 
         return  startProcess(daemonArgs, daemonDir.getVersionedDir(), stdInput);
     }


四. 守护进程执行入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public  class  GradleDaemon {
     public  static  void  main(String[] args) {
         new  ProcessBootstrap().run( "org.gradle.launcher.daemon.bootstrap.DaemonMain" , args);
     }
}
 
 
public  class  DaemonMain  extends  EntryPoint {
 
     private  static  final  Logger LOGGER = Logging.getLogger(DaemonMain. class );
 
     private  PrintStream originalOut;
     private  PrintStream originalErr;
 
     @Override
     protected  void  doAction(String[] args, ExecutionListener listener) {
         ...
 
         KryoBackedDecoder decoder =  new  KryoBackedDecoder( new  EncodedStream.EncodedInput(System.in));
         try  {
             gradleHomeDir =  new  File(decoder.readString());
             daemonBaseDir =  new  File(decoder.readString());
             idleTimeoutMs = decoder.readSmallInt();
             periodicCheckIntervalMs = decoder.readSmallInt();
             daemonUid = decoder.readString();
             int  argCount = decoder.readSmallInt();
             startupOpts =  new  ArrayList<String>(argCount);
             for  ( int  i =  0 ; i < argCount; i++) {
                 startupOpts.add(decoder.readString());
             }
             int  additionalClassPathLength = decoder.readSmallInt();
             additionalClassPath =  new  ArrayList<File>(additionalClassPathLength);
             for  ( int  i =  0 ; i < additionalClassPathLength; i++) {
                 additionalClassPath.add( new  File(decoder.readString()));
             }
         catch  (EOFException e) {
             System.out.println( "DaemonMain doAction 4" );
             throw  new  UncheckedIOException(e);
         }
 
         NativeServices.initialize(gradleHomeDir);
         
         DaemonServerConfiguration parameters =  new  DefaultDaemonServerConfiguration(daemonUid, daemonBaseDir, idleTimeoutMs, periodicCheckIntervalMs, startupOpts);
         
         LoggingServiceRegistry loggingRegistry = LoggingServiceRegistry.newCommandLineProcessLogging();
        
         LoggingManagerInternal loggingManager = loggingRegistry.newInstance(LoggingManagerInternal. class );
         
         TrueTimeProvider timeProvider =  new  TrueTimeProvider();
         
         DaemonServices daemonServices =  new  DaemonServices(parameters, loggingRegistry, loggingManager,  new  DefaultClassPath(additionalClassPath), timeProvider.getCurrentTime());
         
         File daemonLog = daemonServices.getDaemonLogFile();
         
         // Any logging prior to this point will not end up in the daemon log file.
         initialiseLogging(loggingManager, daemonLog);
 
         LOGGER.debug( "Assuming the daemon was started with following jvm opts: {}" , startupOpts);
         
         Daemon daemon = daemonServices.get(Daemon. class );
         daemon.start();
 
         try  {
             DaemonContext daemonContext = daemonServices.get(DaemonContext. class );
             Long pid = daemonContext.getPid();
             daemonStarted(pid, daemon.getUid(), daemon.getAddress(), daemonLog);
             DaemonExpirationStrategy expirationStrategy = daemonServices.get(MasterExpirationStrategy. class );
             daemon.stopOnExpiration(expirationStrategy, parameters.getPeriodicCheckIntervalMs());
         finally  {
             daemon.stop();
         }
     }
}


五. 守护进程的日志

守护进程的日志没有打印在控制台,而是打印在文件中,通过下面这行代码,进行了日志输出流转向。

1
2
// Any logging prior to this point will not end up in the daemon log file.
initialiseLogging(loggingManager, daemonLog);


日志保存的位置在 GRADLE_USER_HOME/daemon/版本号/daemon-进程号.out.log

如果没有配置GRADLE_USER_HOME,那就在根目录。windows的话在'c:\Users\rongwei.huang\.gradle\'


我自己的日志目录是:"d:\gradle_jar_cache\daemon\3.1-snapshot-1\daemon-10972.out.log"


最后附加自己编译的gradle3.1源代码和编译生成文件


gradle3.1源代码


gradle3.1源代码编译后文件



     本文转自rongwei84n 51CTO博客,原文链接:http://blog.51cto.com/483181/1931190,如需转载请自行联系原作者


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
16天前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
118 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
4月前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
60 3
|
5月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
120 0
|
5月前
|
负载均衡 Java 调度
探索Python的并发编程:线程与进程的比较与应用
本文旨在深入探讨Python中的并发编程,重点比较线程与进程的异同、适用场景及实现方法。通过分析GIL对线程并发的影响,以及进程间通信的成本,我们将揭示何时选择线程或进程更为合理。同时,文章将提供实用的代码示例,帮助读者更好地理解并运用这些概念,以提升多任务处理的效率和性能。
90 3
|
5月前
|
消息中间件 程序员 数据处理
探究操作系统中的进程间通信(IPC)机制及其在现代软件开发中的应用
本文深入探讨了操作系统中的核心概念——进程间通信(IPC),揭示了其在现代软件开发中的关键作用。通过对各种IPC机制如管道、消息队列、共享内存等的详细分析,本文旨在为读者提供一个清晰的理解框架,帮助他们掌握如何在实际应用中有效利用这些技术以实现进程间的协同工作。此外,文章还将探讨IPC在高并发环境下的性能优化策略,以及如何避免常见的IPC编程错误。通过结合理论与实践,本文不仅适合希望深入了解操作系统原理的技术人员阅读,也对那些致力于提升软件质量和开发效率的程序员具有重要参考价值。
120 12
|
5月前
|
安全 开发者 Python
Python IPC大揭秘:解锁进程间通信新姿势,让你的应用无界连接
【9月更文挑战第11天】在编程世界中,进程间通信(IPC)如同一座无形的桥梁,连接不同进程的信息孤岛,使应用无界而广阔。Python凭借其丰富的IPC机制,让开发者轻松实现进程间的无缝交流。本文将揭开Python IPC的神秘面纱,介绍几种关键的IPC技术:管道提供简单的单向数据传输,适合父子进程间通信;队列则是线程和进程安全的数据共享结构,支持多进程访问;共享内存允许快速读写大量数据,需配合锁机制确保一致性;套接字则能实现跨网络的通信,构建分布式系统。掌握这些技术,你的应用将不再受限于单个进程,实现更强大的功能。
85 6
|
6月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
6月前
|
Kubernetes Shell 测试技术
在Docker中,可以在一个容器中同时运行多个应用进程吗?
在Docker中,可以在一个容器中同时运行多个应用进程吗?
|
6月前
|
人工智能 PyTorch 算法框架/工具
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
【8月更文挑战第6天】Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
|
6月前
|
Android开发
解决Android、Flutter编译时Gradle报错:javax.net.ssl.SSLException: Connection reset
解决Android、Flutter编译时Gradle报错:javax.net.ssl.SSLException: Connection reset
708 0

热门文章

最新文章

推荐镜像

更多