简体   繁体   English

Spring Boot + Spring MVC + Ratpack可能吗?

[英]Is Spring Boot + Spring MVC + Ratpack possible?

We're a Spring Boot shop and rely heavily on Spring MVC for our REST endpoints. 我们是一个Spring Boot商店,并且非常依赖Spring MVC作为我们的REST端点。 We use Boot and embedded Tomcat to create a self-hosting JAR. 我们使用Boot和嵌入式Tomcat来创建自托管JAR。 Is it possible to replace Tomcat with Ratback while still keeping all my Spring MVC code in place? 是否可以用Ratback替换Tomcat,同时仍然保留我的所有Spring MVC代码? I am afraid that Spring MVC is tied into the servlet specification somehow and will not run without a servlet container. 我担心Spring MVC会以某种方式绑定到servlet规范中,并且不会在没有servlet容器的情况下运行。 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. 我知道dsyer / spring-boot-ratpack的工作,但在略读之后,代码无法决定Spring MVC是否能够很好地使用桥接器。 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? 是否有人知道任何可以让我们保留对Spring MVC的投资并让Spring Boot使用Ratpack来管理HTTP流量的工作?

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?" 我怀疑你的问题的症结可以归结为:“我们可以把我们的Spring控制器放在Ratpack的非阻塞HTTP层之上吗?” 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. 对这个问题最简单的答案是否定的,因为MVC编程模型不能很好地适应被动/ NIO模型。

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. 如果是这种情况,那么控制器中的代码可能已经非阻塞,您可以轻松地将其转换为Ratpack代码。

As an example, consider the following @RestController in a Spring Boot app: 作为示例,请考虑Spring Boot应用程序中的以下@RestController

@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: Spring的数据绑定方面是一个计算过程(即不受I / O限制),因此我们可以轻松地将其转换为Ratpack处理程序:

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: SpringConfig看起来像这样:

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! 希望这可以帮助!

The Spring MVC programming model is not very heavily dependent on Servlet APIs, but it's not supported in any other containers (ie not in Ratpack). Spring MVC编程模型并不是非常依赖于Servlet API,但是在任何其他容器中都不支持它(即不在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. 现在有一些异步的东西,Servlet 3.1增强了它,所以如果这是吸引你的Ratpack的一部分,也许只是使用它将是一个更好的方法。 You won't get all the way to reactive and non-blocking IO that way though. 尽管如此,你不会一直到反应和非阻塞IO。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM