Grails:为什么编译时会执行Config.groovy文件?

时间:2017-09-18 12:39:58

标签: maven grails groovy configuration log4j

来自the Grails documentationthis问题:

  

对于常规配置,Grails提供了两个文件:

     
      
  1. 的grails-app / CONF / BuildConfig.groovy
  2.   
  3. 的grails-app / CONF / Config.groovy中
  4.         

    他们都使用Groovy的ConfigSlurper语法。第一个是BuildConfig.groovy,用于运行Grails命令时使用的设置,例如compile,doc等。第二个文件Config.groovy用于运行应用程序时使用的设置。这意味着Config.groovy与您的应用程序一起打包,但BuildConfig.groovy不是。

这是关于log4j框架的摘录:

  

Grails使用其通用配置机制为底层Log4j日志系统提供设置,因此您所要做的就是将log4j设置添加到文件grails-app / conf / Config.groovy

我有一个包含这两个文件的项目:grails-app/conf/BuildConfig.groovygrails-app/conf/Config.groovy。该项目使用log4j实用程序,因此某些设置(包括函数)放在 Config.groovy 文件中。现在,根据我引用的文档,它是正确的文件,因为我想使用日志实用程序来运行应用程序,而不是编译它。

有趣的是,当我在项目上运行mvn package时,会使用这些设置 - 执行log4j设置中的功能。

根据the documentationthe question,情况并非如此。

我知道可以使用grailsApplication来访问这些设置:

def recipient = grailsApplication.config.foo.bar.hello

所以我搜索了我的项目并发现了grailsApplication的一些用法,但没有与log4j设置有关。

mvn package期间使用 Config.groovy 文件中放置log4j设置的其他可能原因是什么?我错过了什么?

更新:当我第一次使用mvn package构建项目时,上述配置似乎有效。下次运行mvn package时,将使用log4j文件中的Config.groovy配置。如果我删除了工作空间,它又能很好地工作。

2 个答案:

答案 0 :(得分:3)

有一件重要的事情值得一提。尽管应用程序在运行时使用了Config.groovy,但它必须首先编译为Java Config.class。打包应用程序时,编译器必须访问此文件并将其编译为字节码。看一下我下面粘贴的列表,它来自我工作区中的一个Grails应用程序:

命令:

ls -l target/classes | awk '{print $8}'

Ouptput:

application.properties
BootStrap.class
BootStrap$_closure1.class
BootStrap$_closure2.class
BuildConfig.class
BuildConfig$_run_closure1.class
BuildConfig$_run_closure1_closure2.class
BuildConfig$_run_closure1_closure3.class
BuildConfig$_run_closure1_closure4.class
BuildConfig$_run_closure1_closure5.class
com
Config.class
Config$_run_closure1.class
Config$_run_closure1_closure4.class
Config$_run_closure1_closure4_closure5.class
Config$_run_closure1_closure4_closure5_closure6.class
Config$_run_closure2.class
Config$_run_closure2_closure7.class
Config$_run_closure2_closure8.class
Config$_run_closure3.class
DataSource.class
DataSource$_run_closure1.class
DataSource$_run_closure2.class
DataSource$_run_closure3.class
DataSource$_run_closure3_closure4.class
DataSource$_run_closure3_closure4_closure7.class
DataSource$_run_closure3_closure5.class
DataSource$_run_closure3_closure5_closure8.class
DataSource$_run_closure3_closure6.class
DataSource$_run_closure3_closure6_closure9.class
DataSource$_run_closure3_closure6_closure9_closure10.class
resources.class
resources$_run_closure1.class
UrlMappings.class
UrlMappings$__clinit__closure1.class
UrlMappings$__clinit__closure1_closure2.class
UrlMappings$__clinit__closure1_closure2_closure3.class

您可以看到Config.groovy文件已编译为Config.class文件,并且Config.groovy内使用的所有闭包都被编译为Java的匿名类(例如{{1} })。这就是为什么如果你把一些执行任何逻辑的代码放到Config$_run_closure1_closure4.class你必须预期它将被编译和执行,因为编译的类扩展Config.groovy并且它执行Groovy脚本文件的主体。您可以在下面找到groovy.lang.Script文件的外观:

命令:

Groovy.class

输出:

javap -l  target/classes/Config.class

更新

现在要了解执行Compiled from "Config.groovy" public class Config extends groovy.lang.Script { public static transient boolean __$stMC; public static long __timeStamp; public static long __timeStamp__239_neverHappen1501076781354; public Config(); LocalVariableTable: Start Length Slot Name Signature 4 4 0 this LConfig; public Config(groovy.lang.Binding); LocalVariableTable: Start Length Slot Name Signature 4 21 0 this LConfig; 4 21 1 context Lgroovy/lang/Binding; public static void main(java.lang.String...); LocalVariableTable: Start Length Slot Name Signature 0 19 0 args [Ljava/lang/String; public java.lang.Object run(); LineNumberTable: line 14: 4 line 17: 43 line 18: 126 line 24: 194 line 26: 233 line 30: 296 line 31: 323 line 38: 376 line 42: 419 line 45: 453 line 63: 473 line 65: 507 line 68: 550 line 70: 595 line 72: 631 line 74: 679 line 77: 724 line 80: 777 line 84: 822 line 86: 867 line 88: 912 line 99: 932 LocalVariableTable: Start Length Slot Name Signature 0 964 0 this LConfig; public java.lang.Object this$dist$invoke$3(java.lang.String, java.lang.Object); LocalVariableTable: Start Length Slot Name Signature 0 68 0 this LConfig; 0 68 1 name Ljava/lang/String; 0 68 2 args Ljava/lang/Object; public void this$dist$set$3(java.lang.String, java.lang.Object); LocalVariableTable: Start Length Slot Name Signature 0 53 0 this LConfig; 0 53 1 name Ljava/lang/String; 0 53 2 value Ljava/lang/Object; public java.lang.Object this$dist$get$3(java.lang.String); LocalVariableTable: Start Length Slot Name Signature 0 46 0 this LConfig; 0 46 1 name Ljava/lang/String; protected groovy.lang.MetaClass $getStaticMetaClass(); public static void __$swapInit(); static {}; public int super$1$hashCode(); public void super$3$printf(java.lang.String, java.lang.Object); public void super$3$printf(java.lang.String, java.lang.Object[]); public void super$3$setProperty(java.lang.String, java.lang.Object); public boolean super$1$equals(java.lang.Object); public void super$1$finalize(); public groovy.lang.Binding super$3$getBinding(); public void super$3$print(java.lang.Object); public void super$3$setBinding(groovy.lang.Binding); public java.lang.Object super$3$evaluate(java.io.File); public java.lang.String super$1$toString(); public java.lang.Object super$3$evaluate(java.lang.String); public void super$2$setMetaClass(groovy.lang.MetaClass); public void super$1$notify(); public java.lang.Object super$3$invokeMethod(java.lang.String, java.lang.Object); public java.lang.Object super$1$clone(); public void super$1$wait(long, int); public void super$1$wait(long); public void super$1$wait(); public groovy.lang.MetaClass super$2$getMetaClass(); public java.lang.Class super$1$getClass(); public void super$3$run(java.io.File, java.lang.String[]); public void super$3$println(java.lang.Object); public void super$1$notifyAll(); public java.lang.Object super$3$getProperty(java.lang.String); public void super$3$println(); static java.lang.Class class$(java.lang.String); } 的原因,我们需要深入了解Config.groovy执行时会发生什么。运行grails package命令会使grails-core中的grails package脚本被执行。 _GrailsPackage.groovy目标调用packageApp

https://github.com/grails/grails-core/blob/2.4.x/grails-scripts/src/main/scripts/_GrailsPackage.groovy#L48

此方法调用GrailsProjectPackager.packageApplication()助手类:

https://github.com/grails/grails-core/blob/2.4.x/grails-project-api/src/main/groovy/org/codehaus/groovy/grails/project/packaging/GrailsProjectPackager.groovy#L274

createConfig()方法实现中,我们可以找到createConfig()执行:

https://github.com/grails/grails-core/blob/2.4.x/grails-project-api/src/main/groovy/org/codehaus/groovy/grails/project/packaging/GrailsProjectPackager.groovy#L345

这是一个Groovy类,它解析脚本,最后在解析的脚本上调用ConfigSlurper.parse(script)。使用调试器很容易找到 - 在我的视频中查看我在这个特定示例中如何执行此操作:https://www.youtube.com/watch?v=s2PN6TjFjUI

我希望它有所帮助。

答案 1 :(得分:1)

mvn package将运行其他maven阶段,其中包括test阶段。 Grails集成测试将引导您的完整应用程序,以便解析Config.groovy文件。