SpringBoot Undertow:如何调度到工作线程
我目前正在查看springboot,并且对我来说还不是很清楚如何将传入的HTTP请求分派给工作线程以阻止操作处理。
查看类
,由于唯一的HttpHandler是一个ServletHandler,它允许@Controller配置,因此看起来没有这种行为。
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);
}
}
private HttpHandler getContextHandler(HttpHandler servletHandler) {
if (StringUtils.isEmpty(this.contextPath)) {
return servletHandler;
}
return Handlers.path().addPrefixPath(this.contextPath, servletHandler);
}
默认情况下,在undertow中,所有请求均由IO-
Thread处理以进行非阻塞操作。这是否意味着每个@Controller执行将由非阻塞线程处理?还是有从IO-THREAD或WORKER-
THREAD中选择的解决方案?
我尝试编写一种解决方法,但是此代码非常笨拙,也许有人有更好的解决方案:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BlockingHandler {
String contextPath() default "/";
}
public class UndertowInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
configurableApplicationContext.addBeanFactoryPostProcessor(new UndertowHandlerPostProcessor());
}
}
public class UndertowHandlerPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(BlockingHandler.class));
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("org.me.lah")){
try{
Class clazz = Class.forName(beanDefinition.getBeanClassName());
beanDefinitionRegistry.registerBeanDefinition(clazz.getSimpleName(), beanDefinition);
} catch (ClassNotFoundException e) {
throw new BeanCreationException(format("Unable to create bean %s", beanDefinition.getBeanClassName()), e);
}
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//no need to post process defined bean
}
}
public class UndertowEmbeddedServletContainerFactory extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware, ApplicationContextAware { private ApplicationContext applicationContext;
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {
DeploymentManager manager = createDeploymentManager(initializers);
int port = getPort();
if (port == 0) {
port = SocketUtils.findAvailableTcpPort(40000);
}
Undertow.Builder builder = createBuilder(port);
Map<String, Object> handlers = applicationContext.getBeansWithAnnotation(BlockingHandler.class);
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
port, port >= 0, handlers);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
...
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager, String contextPath, int port, boolean autoStart, Map<String, Object> handlers) {
this.builder = builder;
this.manager = manager;
this.contextPath = contextPath;
this.port = port;
this.autoStart = autoStart;
this.handlers = handlers;
}
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
String path = this.contextPath.isEmpty() ? "/" : this.contextPath;
PathHandler pathHandler = Handlers.path().addPrefixPath(path, servletHandler);
for(Entry<String, Object> entry : handlers.entrySet()){
Annotation annotation = entry.getValue().getClass().getDeclaredAnnotation(BlockingHandler.class);
System.out.println(((BlockingHandler) annotation).contextPath());
pathHandler.addPrefixPath(((BlockingHandler) annotation).contextPath(), (HttpHandler) entry.getValue());
}
this.builder.setHandler(pathHandler);
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
public static void main(String[] args) { new SpringApplicationBuilder(Application.class).initializers(new UndertowInitializer()).run(args);
}
@BlockingHandler(contextPath = "/blocking/test")public class DatabaseHandler implements HttpHandler {
@Autowired
private EchoService echoService;
@Override
public void handleRequest(HttpServerExchange httpServerExchange) throws Exception {
if(httpServerExchange.isInIoThread()){
httpServerExchange.dispatch();
}
echoService.getMessage("my message");
}
}
如您所见,我的“解决方案”实在太繁重了,我非常感谢您提供的许多简化方面的帮助。
谢谢
回答:
您什么都不需要做。
Spring Boot的默认Undertow配置ServletInitialHandler
在Spring
MVC的前面使用Undertow
的DispatcherServlet
。该处理程序执行exchange.isInIoThread()
检查并dispatch()
在必要时调用。
如果在中放置一个断点@Controller
,则会看到在名为XNIO-1
task-nworker线程的线程上调用了该断点(IO线程的名称为XNIO-1 I/O-n
)。
以上是 SpringBoot Undertow:如何调度到工作线程 的全部内容, 来源链接: utcz.com/qa/434823.html