在我的previous question(謝謝@Andy Wilkinson)中,我發現所有到undertowEmbeddedServletContainer
的傳入請求都由工作線程(阻塞操作)處理。Spring Boot Undertow在同一應用程序中添加阻塞處理程序和NIO處理程序
根據Andy的說法,我嘗試添加一個UndertowBuilderCustomizer
以覆蓋ServletInitializerHandler
以使用非阻塞處理程序處理傳入請求。
@Bean
public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory(){
UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory = new UndertowEmbeddedServletContainerFactory();
undertowEmbeddedServletContainerFactory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Undertow.Builder builder) {
builder.setHandler(new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.getResponseSender().send("test");
}
});
}
});
return undertowEmbeddedServletContainerFactory;
}
在這種定製我設定的建設者rootHandler
的NIO處理程序。 但它是由UndertowEmbeddedServletContainer
在啓動階段重寫了ServletInitializerHandler
:
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
this.builder.setHandler(getContextHandler(servletHandler));
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
由於這個問題的標題說:我想有阻塞和非阻塞處理,其中阻塞處理程序通過@Controller
管理註釋,以及Spring處理NIO處理程序的位置。
我找到了一個解決方案,但作爲初學者,我不知道它是否是一個好的解決方案。
HandlerPath註釋
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.TYPE})
public @interface HandlerPath {
public String path() default "";
}
創建豆實現的HttpHandler
@Component
@HandlerPath(path = "/hello-nio")
public class HelloHandler implements HttpHandler{
@Autowired
HelloService helloService;
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.getResponseSender().send(helloService.sayHello("Josselin"));
}
}
創建一個簡單的控制器
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String sayHello(){
return "hello";
}
}
創建類實施ServletExtension
public class NonBlockingHandlerExtension implements ServletExtension{
@Override
public void handleDeployment(DeploymentInfo deploymentInfo, final ServletContext servletContext) {
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
@Override
public HttpHandler wrap(final HttpHandler handler) {
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Map<String, Object> handlers = ctx.getBeansWithAnnotation(HandlerPath.class);
PathHandler rootHandler = new PathHandler();
rootHandler.addPrefixPath("/", handler);
for(Map.Entry<String, Object> handlerEntry : handlers.entrySet()){
if(handlerEntry.getValue() instanceof HttpHandler){
HttpHandler httpHandler = (HttpHandler) handlerEntry.getValue();
String path = httpHandler.getClass().getAnnotation(HandlerPath.class).path();
rootHandler.addPrefixPath(path, httpHandler);
}
}
return rootHandler;
}
});
}
}
在該方法中,默認ServletInitializer
處理程序綁定到「/」上下文,並且管理由彈簧,因此,所有阻止請求可以通過@Controller
(多個)進行處理。 然後,我嘗試發現所有註釋爲@HandlerPath
的豆,然後根據@HandlerPath.path
屬性向rootHandler
添加新的prefixPath
。
最後
創建一個目錄META-INF.services
創建一個文件io.undertow.servlet.ServletExtension,並添加一行:
org.me.undertow.NonBlockingHandlerExtension
結果
所有工作都像一個魅力,NIO處理程序被稱爲bi時找到URL,所以阻止處理程序。
任何人都可以請讓我知道,如果這種解決方案可以改善任何方式? 此外,由於NIO處理程序的URL不是由Spring管理的,我想我必須使用globaleMethodSecurity
並設置來保護NIO處理程序?