playframework/playframework — pull request #2622 by richdougherty (2014-04-09 00:01:57+00:00)
Title: Optimize router HandlerInvoker construction and lookup

Before this change routers created a HandlerInvoker for every request. With this change, each route's HandlerInvoker is created once and cached in its own lazy val.

We can use the cached HandlerInvoker to cache route information such as Java reflection info and request tags. That lets us remove the ConcurrentHashMap that was previously used to cache Java reflection info.

These changes improves both Scala and Java performance, but Java performance improves the most.

To implement the change, we change all the implicits that we previously used for creating HandlerInvokers into implicits for creating HandlerInvokerFactories. HandlerInvokerFactories are used to create the HandlerInvokerFactory for each route.

We need to use a hack to implicitly resolve the correct HandlerInvokerFactory.

Before, HandlerInvokers were implicitly resolved while a request was being handled. That meant that the correct implicit HandlerInvoker could be found by calling the controller method with the request parameters.

Now, we can't call the controller method, since we want to create a HandlerInvokerFactories even when we're not handling a request, so we can't call the controller method with the request parameters.

What we do instead is *pretend* to call the controller method in a call-by-name thunk, but never actually call that thunk.

It's a bit hacky, but it works. Maybe in the future we could use macros to directly get the return type of the controller method.