@PostConstruct在Grails服务中默默失败

8
我原以为在Grails环境中,Spring注解应该可以直接使用,但实际上我无法让它正常工作。我还尝试了afterProperties方法,但也没有成功。
有人能发现错误吗?是否需要进行某些配置?
package dashboard

import javax.annotation.PostConstruct

class EmailJobSchedulerService
{
    def grailsApplication

    @PostConstruct
    def init() {
        def cronExpression = grailsApplication.config.emailAt8AmTrigger
        println(cronExpression)
        EmailSubscribersJob.schedule(cronExpression, new HashMap())
    }
}

那个注解设置了很多限制(请参见http://docs.oracle.com/javase/7/docs/api/javax/annotation/PostConstruct.html)。它们都适用吗? - lucke84
@lucke84 根据Ian的建议将其更改为void后,我应该遵守所有约束条件。 - willcodejavaforfood
4
你希望cronExpression何时被打印出来?在服务器启动时吗?我认为它将在第一次调用任何服务方法时调用,而不是在服务器启动时。我建议在引导程序中调用一个虚拟方法以确认。 - uchamp
@uchamp 我期望它在Spring完成配置我的bean后被调用。 - willcodejavaforfood
2个回答

17

尝试将其更改为

@PostConstruct
void init() {

(即使用void而不是def)。我不确定Spring是否特别强制执行此操作,但是 @PostConstruct 的规范指出,方法的返回类型必须为void

编辑:uchamp的评论是正确的,我刚尝试了相同的测试,确实仅在第一次使用服务bean时调用@PostConstruct注释的方法,并不一定立即启动。你可以添加

static lazyInit = false

为了在启动时强制初始化服务类,可以将其配置为“eagerly”。这似乎没有在用户指南中记录,我是通过阅读代码推断出来的。

请注意,上一段落中的“使用”并不一定意味着必须对其调用方法。服务bean将在第一次从应用程序上下文中获取时进行初始化,直接获取或者因为它已被自动装配到另一个正在初始化的bean中。例如,使用以下方式将服务注入到 BootStrap 中:

def emailJobSchedulerService

仅调用BootStrap.init闭包即可足以触发@PostConstruct方法,不需要实际从服务中调用任何方法。同样地,如果您的服务被注入到任何控制器中,那么只要这些控制器处理请求(任何请求都可以,不一定是调用服务的操作),则会在第一次启动时启动。


仍然没有任何进展。不过还是感谢你的努力 :) - willcodejavaforfood
2
假设所讨论的.groovy文件位于grails-app/services而不是src/groovy,那么它应该可以正常工作。我已经使用过相同的技巧很多次了。但需要注意的一点是,在@PostConstruct时间GORM可能不可用。如果您需要执行任何GORM方法,则可能需要定义一个普通的非注释方法,并从BootStrap中调用它。 - Ian Roberts
这很奇怪。我甚至使用命令行创建了一个全新的项目,@PostConstruct也没有被调用。我不需要为此使用GORM,只需安排我的作业即可,该作业不会被持久化。 - willcodejavaforfood
经过更深入的挖掘,似乎 static lazyInit = false 是你要找的。@willcodejavaforfood - Ian Roberts
太棒了!不知道有这个选项。 - uchamp

2

仅在 @Ian 的回答上补充一点 - 由于某些原因,我有:

@PostConstruct
private void init() {

这也会默默失败并出现奇怪的行为。解决方法是删除“private”:
@PostConstruct
void init() {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接