为什么Grails推荐singleton作用域作为控制器的动作方法? [英] Why does Grails recommend singleton scope for controllers with actions as methods?

查看:137
本文介绍了为什么Grails推荐singleton作用域作为控制器的动作方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道早期版本的Grails使用控制器的原型范围,因为当时所有的操作都是关闭的。



我知道当前版本文档建议使用singleton作用域控制器使用方法作为动作的控制器。

从以下文章看来,方法和单例范围更受欢迎或推荐,但尚不清楚为什么。


tp:// grails.1312388.n4.nabble.com/Default-scope-for-controllers-doc-td4657986.html



我们有一个使用原型的大型项目作为方法的作用域的控制器。更改为推荐的控制器范围涉及风险和重新测试,并从现有控制器中删除任何非单体友好状态。



我想知道为什么Grails建议单身作用域作为动作控制器的方法?是不是因为这比Spring MVC更常见和相似,并且避免了混淆,或者是否有改进性能的机会,或者是什么? 如果我切换到单身控制器,我会得到什么?如果我不做这个开关,费用是多少?

解决方案

我对Rails没有太多的工作,但是(至少在我玩过的版本中,现在的情况可能会有所不同)控制器就是模型,它包含了视图要渲染的数据。在处理请求的过程中,您可以在切换处理以查看渲染器之前将值存储在控制器实例字段中。因此,为每个请求创建一个新的控制器实例是非常有意义的,因此它们是截然不同的。



Grails受Rails启发,并使用其中的几个约定,最着名的约定-over配置。但使用控制器作为模型的能力也被添加为一个功能,虽然它没有很好的记录,我怀疑许多人使用它。



典型的方式a当使用GSP来呈现响应时(与转发或重定向相反,或直接在控制器中呈现,例如使用 render foo作为JSON ),控制器操作将返回一个由于它在Groovy中是可选的,所以省略了 return 关键字的映射关键字/值对中的一个或多个键/值对。

  class MyController {
def someAction(){
def theUser = ...
def theOtherObject = ...
[ user:theUser,other:theOtherObject]
}
}

这里模型map有两个条目,其中一个由 user 键控,另一个由 other 键控,并且这些将是使用的变量名称在普惠制访问数据。



但是大多数人不知道是你也可以这样做:

  class MyController {

def user
def其他

def someAction(){
user = ...
other = ...
}
}

在这种情况下,模型映射不会从动作中返回,所以Grails会从控制器类的所有属性中填充模型,在这种情况下,相同的GSP将适用于这两种方法,因为第二种方法中的变量名称与第一种中的地图键相同。



使控制器单身人士在2.0中被添加(在技术上1.4被重新命名为2.0之前,请参阅 JIRA问题< a>),除了保留对关闭的支持之外,我们还增加了对方法的支持。最初的假设是,使用闭包可以启用一些有趣的功能,但从未发生过。使用方法更自然,因为您可以在子类中重写它们,而不像闭包那样只是类作用域。



作为2.0返工的一部分,我们移除了Rails灵感功能的假设是,因为它基本上没有文档,因此对使用该功能的少数奇怪应用程序的影响不会很大。尽管控制器类通常很容易垃圾回收,并且每个请求创建一个实例并不会影响太多,但是我不记得有人抱怨过这个功能会丢失。



,很少需要控制器中的每个请求状态,所以单例通常更有意义。默认的原型范围是为了向后兼容而留下的,但使用Config.groovy属性(和由 create-app 脚本生成的文件执行此操作)很容易更改默认值。尽管每个请求都会得到新的请求和响应,并且如果使用了会话,每个用户都将拥有自己的请求和响应,但这些不是控制器的实例字段。它们看起来像是因为我们可以访问请求响应会话 params 等等,但这些实际上是 getRequest() getResponse() getSession() getParams()方法。这些方法不是作为类字段,而是通过ThreadLocals访问它们的对象,因此存在每个请求状态,但它不存储在控制器实例中。



我不记得是基准测试比较了使用方法和封闭方法,但是Lari Hotari可能做了一些。如果有差异,可能并不重要。您可以在自己的应用程序中通过转换一个或几个控制器并在测试之前和之后进行测试。如果两种方法之间的性能,缩放和内存差异不显着,则可能会安全地保留原型分数和/或关闭。如果存在差异,并且您的控制器中没有实例字段,那么转换为单例和方法可能是值得的。

如果你确实有实例字段,它们可以转换为请求属性 - request.foo = 42 是一个 request.setAttribute('foo',42)的metaclass快捷方式,所以您可以安全地将每个请求数据存储在那里。


I know early versions of Grails used prototype scope for controllers because actions were all closures at that time.

I know that the current version documentation recommends singleton scoped controllers for controllers that use methods as actions.

From the following post it seems that methods and singleton scope are more desirable or recommended, but it's not clear why.
ttp://grails.1312388.n4.nabble.com/Default-scope-for-controllers-doc-td4657986.html

We have a large project that uses prototype scoped controllers with actions as methods. Changing to the recommended controller scope involves risk and retesting, and removing any non-singleton friendly state from existing controllers.

I'd like to know why does Grails recommend singleton scope for method as actions controllers? Is it just because that's more common and similar to Spring MVC, and avoids confusion, or is there an opportunity for performance improvement, or what? What do I gain if I make the switch to singleton controllers? What is the cost if I don't make the switch?

解决方案

I haven't worked much with Rails, but (at least in the versions I played with, things may be different now) the controller is the model, containing the data to be rendered by the view. During request handling you store values in controller instance fields before handing off processing to view renderers. So there it makes sense to create a new controller instance for each request so they're distinct.

Grails was inspired by Rails and uses several of its conventions, most famously convention-over-configuration. But the ability to use the controller as the model was also added as a feature, although it wasn't well documented and I doubt many used it.

The typical way a controller action works when using a GSP to render the response (as opposed to forwarding or redirecting, or rendering directly in the controller, e.g. with render foo as JSON) is to return a Map with one or more key/value pairs from the action, and often the return keyword is omitted since it's optional in Groovy:

class MyController {
   def someAction() {
      def theUser = ...
      def theOtherObject = ...
      [user: theUser, other: theOtherObject]
   }
}

Here the model map has two entries, one keyed by user and the other keyed by other, and those will be the variable names used in the GSP to access the data.

But what most people don't know is that you could also do it like this:

class MyController {

   def user
   def other

   def someAction() {
      user = ...
      other = ...
   }
}

In this case a model map isn't returned from the action, so Grails would populate the model from all properties of the controller class, and in this case the same GSP would work for both approaches since the variable names in the second approach are the same as the map keys in the first.

The option to make controllers singletons was added in 2.0 (technically 1.4 before it was renamed to 2.0, see this JIRA issue) and we also added support for methods as actions in addition to retaining support for closures. The original assumption was that using closures would enable some interesting features, but that never happened. Using methods is more natural since you can override them in subclasses, unlike closures which are just class-scope fields.

As part of the 2.0 rework we removed that Rails-inspired feature on the assumption that since it was essentially undocumented, that the impact on the few odd apps that used the feature wouldn't be significant. I don't recall anyone ever complaining about the loss of that feature.

Although controller classes are typically readily garbage-collectible and creating an instance per request doesn't affect much, it's rare to need per-request state in a controller, so singletons usually make more sense. The default prototype scope was left for backwards compatibility but it's easy to change the default with a Config.groovy property (and the file generated by the create-app script does this).

Although each request does get a new request and response, and if sessions are used each user will have their own, but those are not instance fields of the controllers. They look like they are because we can access request, response, session, params, etc. inside of actions, but those are actually the property access forms of the getRequest(), getResponse(), getSession(), and getParams() methods that are mixed into all controllers during compilation by AST transforms. The methods access their objects not as class fields but via ThreadLocals, so there is per-request state but it's not stored in the controller instance.

I don't remember if there was much in the way of benchmarking to compare using methods versus closures, but Lari Hotari probably did some. If there was a difference it was probably not significant. You could test this in your own application by converting just one or a few controllers and doing before and after tests. If the performance, scaling, and memory differences aren't significant between the two approaches you'll probably be safe staying with prototype score and/or closures. If there is a difference and you don't have instance fields in your controllers, then it'll probably be worth the effort to convert to singletons and methods.

If you do have instance fields they can probably be converted to request attributes - request.foo = 42 is a metaclass shortcut for request.setAttribute('foo', 42), so you could store per-request data safely there instead.

这篇关于为什么Grails推荐singleton作用域作为控制器的动作方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆