Grails 3 控制器作用域

Grails 3 Controller Scope

Grails 3 documentation,下面写的是作用域:

prototype (default) - A new controller will be created for each request (recommended for actions as Closure properties)

这里奇怪的是,如果我明确声明,我在 Grails 3.1.4 中得到的结果明显不同:

static scope = "prototype"

以下面的UserController为例

class UserController {
    def userService
    List<String> users

    def loadUsers() {
        if (!users) {
            println("########## have to load users");
            try {
                user = userService.getAllUsersInAd()
            } catch (Exception e) {
                // do something
            }
        } else {
            println("########## dont have to do it " + users.size());
        }
    }
}

还有下面的UserService

class UserService {
    def getAllUsersInAd() {
        println("######### querying")
        return new ArrayList<String>();
    }
}

如果省略静态范围:

当我关闭 Firefox 浏览器并重新打开它时,"dont have to do it is executed",无论我 close/reopen 多少次。更奇怪的是,当我关闭 Firefox 时,我可以打开一个完全不同的浏览器(如 chrome),并执行相同的消息。这个控制器的作用域几乎与 JSF 的 @ApplicationScope 相似。 经过 5-10 分钟的空闲时间后,查询再次执行,但场景仍然存在。

如果声明静态作用域:

每次关闭浏览器后,"have to load users" 都会按预期执行。

我的问题是,默认范围的文档是否有误?如果不是,那么显式声明 scope="prototype" 和省略它(除了上面明显的)有什么区别?

是的,我相信不久前控制器默认更改为单例(应用程序)范围(碰巧是版本 1.4.x)。我正在尝试查找相关文档。它似乎是一个 JIRA 问题修复,最初是 here,但 Grails 已经离开 JIRA,并且没有将所有错误迁移到 GitHub。

根据 Grails 团队的说法,您无论如何都不应该在控制器中拥有状态: 看到 Burt 的回答,Jeff 甚至在评论中发声。

编辑:正如 Jeff 所说,默认仍然是原型,但默认生成的配置将它们全部更改为单例,这是推荐的。

在为 Grails 3.1.4 应用程序默认生成的 application.yml 文件中,您应该会看到如下设置:

grails:
    controllers:
        defaultScope: singleton

这告诉框架使控制器成为单例。如果未设置该设置,则默认范围为 prototype