以前の質問(@Andy Wilkinson に感謝) で、への着信要求はすべてワーカーundertowEmbeddedServletContainer
スレッド (ブロック操作) によって処理されることがわかりました。
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
アノテーションによって管理され、NIO ハンドラーは Spring によって管理されます。
解決策を見つけましたが、初心者として、それが良いものかどうかわかりません。
HandlerPath アノテーション
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.TYPE})
public @interface HandlerPath {
public String path() default "";
}
HttpHandler を実装する Bean を作成する
@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;
}
});
}
}
このメソッドでは、デフォルトハンドラーは "/" コンテキストにバインドされ、Spring によって管理されるため、すべてのブロッキング リクエストは(s)ServletInitializer
によって処理できます。@Controller
次に、 で注釈が付けられたすべての Bean を検出してから、based onプロパティに@HandlerPath
新しい を追加しようとします。prefixPath
rootHandler
@HandlerPath.path
ついに
ディレクトリ META-INF.services を作成します
ファイル io.undertow.servlet.ServletExtension を作成し、次の行を追加します。
org.me.undertow.NonBlockingHandlerExtension
結果
すべてが魅力のように機能し、バインディング URL がヒットすると NIO ハンドラーが呼び出され、ブロッキング ハンドラーも呼び出されます。
このソリューションを何らかの方法で改善できるかどうか、誰かに教えてもらえますか? さらに、NIO ハンドラーの URL は Spring によって管理されていないため、NIO ハンドラーを保護するために使用globaleMethodSecurity
および設定する必要があると思いますか?@PreAuthorize