We're a Spring Boot shop and rely heavily on Spring MVC for our REST endpoints. We use Boot and embedded Tomcat to create a self-hosting JAR. Is it possible to replace Tomcat with Ratback while still keeping all my Spring MVC code in place? I am afraid that Spring MVC is tied into the servlet specification somehow and will not run without a servlet container. I am aware of dsyer/spring-boot-ratpack work but after skimming the code couldn't decide if Spring MVC would play well using the bridge. Is anyone aware of any work that will allow us to retain our investment in Spring MVC and have Spring Boot use Ratpack to manage HTTP traffic?
2 Answers
I suspect the crux of your question can be distilled to: "can we put our Spring controllers on top of Ratpack's non-blocking HTTP layer?" and the simplest answer to that question is no, for reason that the MVC programming model doesn't fit well into the reactive/NIO model very well.
However, if your application has followed some common model-view-controller-(and service) patterns, then your controllers should really just be performing data binding and parsing and delegating out to a service layer. If that's the case, then likely the code in your controller is already non-blocking, and you could easily translate it to Ratpack code.
As an example, consider the following @RestController
in a Spring Boot app:
@RestController
@RequestMapping("/user")
class UserController {
@Autowired
UserService userService
@RequestMapping(method = RequestMethod.POST)
Long create(@RequestBody @Valid User user) {
User savedUser = userService.save(user)
return savedUser.id
}
}
Spring's data binding aspect is a computation process (ie isn't I/O bound), so we can easily translate this into a Ratpack handler:
import app.SpringConfig
import app.User
import app.UserService
import org.springframework.boot.SpringApplication
import org.springframework.context.ApplicationContext
import ratpack.jackson.JacksonModule
import static ratpack.groovy.Groovy.ratpack
import static ratpack.jackson.Jackson.fromJson
import static ratpack.jackson.Jackson.json
import static ratpack.spring.Spring.spring
ratpack {
bindings {
add(new JacksonModule())
bindInstance(ApplicationContext, SpringApplication.run(SpringConfig))
}
handlers { ApplicationContext ctx ->
register(spring(ctx))
prefix("user") {
handler { UserService userService ->
byMethod {
post {
def user = parse(fromJson(User))
blocking {
userService.save(user)
} then { User savedUser ->
render(json(savedUser))
}
}
}
}
}
}
}
Where SpringConfig
looks like this:
package app
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class SpringConfig {
@Bean
UserService userService() {
new UserService()
}
}
And here's a functional test to prove it:
package app
import com.fasterxml.jackson.databind.ObjectMapper
import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest
import ratpack.test.ApplicationUnderTest
import ratpack.test.http.TestHttpClient
import spock.lang.Shared
import spock.lang.Specification
import static groovy.json.JsonOutput.toJson
class FuncSpec extends Specification {
@Shared ApplicationUnderTest aut = new GroovyRatpackMainApplicationUnderTest()
@Shared ObjectMapper mapper = new ObjectMapper()
@Delegate TestHttpClient client = aut.httpClient
def "should parse and save user"() {
given:
def user = new User(username: "dan", email: "danielpwoods@gmail.com")
when:
requestSpec { spec ->
spec.body { b ->
b.type("application/json")
b.text(toJson(user))
}
}
post('user')
then:
def savedUser = mapper.readValue(response.body.text, User)
and:
savedUser.id
}
}
Hope this helps!

- 1,029
- 7
- 10
-
Great answer. I believe our layering is sound where the controllers are mostly there to handle the HTTP adaptation before handing of to service beans that do the heavy lifting, so I believe your suggested model will work for us. Daniel, would our annotation-based exception handlers have to be ported to the Ratpack API or would they magically work as-is? – user1836542 Feb 20 '15 at 12:39
-
Since they interface at the controller/webmvc layer, they'd need to be ported, but that's a pretty seamless process in Ratpack. The only requirements is an `ErrorHandler` impl be available in the registry. https://github.com/ratpack/ratpack/blob/master/ratpack-core/src/main/java/ratpack/error/internal/ErrorHandler.java#L22 – Daniel Woods Feb 20 '15 at 18:41
-
@DanielWoods Will your upcoming book on Ratpack have any info on how to run Ratpack with Spring Boot? – geoand Oct 20 '15 at 10:11
-
@geoand I've been trying to find the right place in the book to fit it in, I'm confident I will. In the meantime, there's this => http://www.infoq.com/articles/Ratpack-and-Spring-Boot – Daniel Woods Oct 20 '15 at 14:09
-
@DanielWoods Thanks a lot for the pointer! I also issued a PR for a demo project you had created on GitHub using Spring Boot + Ratpack. – geoand Oct 20 '15 at 14:36
The Spring MVC programming model is not very heavily dependent on Servlet APIs, but it's not supported in any other containers (i.e. not in Ratpack). There is some async stuff there now and Servlet 3.1 enhances it some more, so if that's the part of Ratpack that attracts you, maybe just using that would be a better approach. You won't get all the way to reactive and non-blocking IO that way though.

- 56,583
- 10
- 155
- 143
-
Dave, interesting idea. I am definitely interested in the reactive stuff that Ratpack provides but I am also interested in its start time and its perceived leanness when compared to Tomcat. Many features that Tomcat provides us go unused. As we journey down the microservices path, I find that we are starting and stopping applications all the time, especially in the context of CI. Having smaller, faster starting applications should help shrink our cycle times. It also wouldn't hurt if we could scale with less resources. – user1836542 Feb 20 '15 at 12:49
-
Fair point, maybe, but I'm not really convinced on the startup time argument until you write the same app on both platforms with equivalent features and security (most of the startup time out of the box with Tomcat is made up of application code or initializing session entropy). BTW watch out later this year for some superfast dev cycle restarts on the platform of your choice (Tomcat included) - Phil Webb is working on something. – Dave Syer Feb 20 '15 at 13:32
-
@DaveSyer Can you give away any more information on what Phil is working on :)? – geoand Feb 27 '15 at 12:38
-
You can probably find something in his fork of Spring Boot. There's more to it than that, but it's a classloader that throws local classes away if anything changes. Spring loads the context again and it's usually super fast. No agents and no byte code trickery. – Dave Syer Feb 27 '15 at 15:18