Мы являемся магазином Spring Boot и в значительной степени полагаемся на Spring MVC для наших конечных точек REST. Мы используем Boot и встроенный Tomcat для создания самообслуживания JAR. Можно ли заменить Tomcat Ratback, сохраняя при этом весь мой код Spring MVC? Я боюсь, что Spring MVC каким-то образом привязана к спецификации сервлета и не будет работать без контейнера сервлетов. Мне известно о работе dsyer/spring-boot-ratpack, но после того, как skimming код не смог решить, будет ли Spring MVC играть с использованием моста. Кто-нибудь знает о какой-либо работе, которая позволит нам сохранить наши инвестиции в Spring MVC и использовать Spring Boot с помощью Ratpack для управления HTTP-трафиком?Возможно ли Spring Boot + Spring MVC + Ratpack?
ответ
Модель программирования Spring MVC не очень сильно зависит от API сервлетов, но она не поддерживается ни в каких других контейнерах (то есть не в Ratpack). Теперь есть некоторые асинхронные вещи, и Servlet 3.1 улучшает его еще больше, поэтому, если это часть Ratpack, которая вас привлекает, возможно, просто использование этого будет лучшим подходом. Тем не менее, вы все равно не доберетесь до реактивного и неблокирующего IO.
Я подозреваю, что суть вашего вопроса может быть переделана так: «можем ли мы установить наши контроллеры Spring поверх неблокирующего HTTP-слоя Ratpack?» и самый простой ответ на этот вопрос - нет, потому что модель программирования MVC не очень хорошо вписывается в реактивную/NIO-модель.
Однако, если ваше приложение выполнило некоторые общие шаблоны model-view-controller- (и service), тогда ваши контроллеры должны просто выполнять привязку данных и разбор и делегирование на уровень обслуживания. Если это так, то, скорее всего, код в вашем контроллере уже не блокируется, и вы можете легко перевести его в код Ratpack.
В качестве примера рассмотрим в Spring загрузки приложения следующий @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 в связывании аспект является процесс вычисления (т.е. не 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))
}
}
}
}
}
}
}
Где SpringConfig
выглядит следующим образом:
package app
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class SpringConfig {
@Bean
UserService userService() {
new UserService()
}
}
А вот функциональный тест, чтобы доказать:
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: "[email protected]")
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
}
}
Надеется, что это помогает!
Отличный ответ. Я считаю, что наше расслоение звучит, когда контроллеры в основном работают с адаптацией HTTP до передачи сервису beans, который делает тяжелую работу, поэтому я считаю, что предлагаемая вами модель будет работать для нас. Даниэль, наши обработчики исключений на основе аннотаций должны быть перенесены в API Ratpack или они будут магически работать как есть? – user1836542
Поскольку они взаимодействуют на уровне контроллера/webmvc, их нужно будет портировать, но это довольно простой процесс в Ratpack. Единственные требования - «ErrorHandler» impl доступны в реестре. https://github.com/ratpack/ratpack/blob/master/ratpack-core/src/main/java/ratpack/error/internal/ErrorHandler.java#L22 –
@DanielWoods В вашей будущей книге о Ratpack есть информация о как запустить Ratpack с Spring Boot? – geoand
Dave, интересная идея. Я определенно интересуюсь реактивным материалом, который предлагает Ratpack, но меня также интересует его время начала и его воспринимаемая худоба по сравнению с Tomcat. Многие функции, которые Tomcat предоставляет нам, не используются. Когда мы путешествуем по пути микросервисов, я обнаруживаю, что мы все время запускаем и останавливаем приложения, особенно в контексте CI. Наличие меньших, более быстрых стартовых приложений должно помочь сократить время цикла. Было бы также не больно, если бы мы могли масштабироваться с меньшими ресурсами. – user1836542
Справедливая точка, может быть, но я не уверен в аргументе времени запуска, пока вы не напишите одно и то же приложение на обеих платформах с эквивалентными функциями и безопасностью (большая часть времени запуска из коробки с Tomcat составлена из кода приложения или инициализации энтропии сеанса). BTW смотрят позже в этом году, когда какой-то сверхбыстрый цикл dev возобновляется на платформе по вашему выбору (включая Tomcat) - Фил Вебб работает над чем-то. –
@DaveSyer Можете ли вы дать больше информации о том, над чем работает Фил :)? – geoand