我做了一些实验,这里有一些结论。这都是实证研究;如果我错了,请纠正我。
首先,很容易看出,当调用constraints
被评估时。只需添加一些调试输出:
static constraints = {
println "Entering constraints..."
name(blank:false, maxSize:50)
// etc.
println "Exiting constraints..."
}
您会看到它确实在应用程序启动时进行了评估。由于某种我不明白的原因,它通常被评估两次。另请注意,它constraints
被标记为静态,因此它与class Race
.
接下来,很容易发现name
,startDate
等确实是函数调用。只需尝试在不存在的属性上指定约束:
static constraints = {
no_such_thing(nullable:true)
}
你将无法做到这一点!结果:
Error Error executing script Shell: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory':
Invocation of init method failed; nested exception is org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException:
No signature of method: Race.no_such_thing() is applicable for argument types: (java.util.LinkedHashMap) values: [[nullable:true]]
当然,您从未定义过所有这些方法,即name
,startDate
等,并且您也没有从其他任何东西继承您的域类。但由于 Grails 将其识别为领域类,它利用 Groovy 的强大功能将方法注入到对象中,绕过了传统面向对象编程的限制。
现在,它并没有真正将方法注入到对象中。您可以轻松检查:
static constraints = {
println Race.metaClass.methods*.name.sort().unique()
// You can even construct an object if you really want to mess with the framework
println new Race().metaClass.methods*.name.sort().unique()
}
您将看不到任何名为name
,startDate
等的方法,并且您也不能println Race.name
在constraints { }
块内。我认为发生的情况是,Groovy 拦截了对不存在的方法Race.name
、Race.startDate
等的调用,并将此约束信息记录在其他地方以供将来使用。如果您愿意,请尝试实际实现名为 eg 的方法Race.name
;我想我可以通过这样做来防止约束起作用,但我无法重现它。
关于何时评估什么的问题,我认为我们在这里对 Groovy 闭包有些困惑。看一眼
startDate(validator: {return (it > new Date())})
这里我们有一个闭包:{return (it > new Date())}
。如果 Groovy 是像 Python 这样的纯解释型语言,它只会存储这个文字代码并在每次调用时重新解释它。因此,您还将获得最新的日期。我的猜测是,Groovy 模仿了这种行为,即使那些代码可能已经编译:它会将此代码包装到一个闭包对象中,并在每次请求验证时调用此对象。这个闭包对象将被存储在某个地方;大概是在存储所有其他约束的同一位置。由于闭包的性质而产生了混乱:如果您存储3
,它将永远存在3
;如果您存储一个闭包(一个函数),它可以在不同的场合评估不同的结果。
重申一下,代码
{return (it > new Date())}
在应用程序启动时未“执行”或“评估”;它仅被存储以备将来使用。您可以轻松检查它:
static constraints = {
startDate(validator: {println "Validating startDate..."})
}
然后运行grails shell
并
groovy> (new Race()).validate()