2014-12-17 2 views
1

В настоящее время я смотрю весенний баттон, и это не совсем ясно (для меня), как отправить входящий HTTP-запрос в рабочий поток для блокировки обработки операций.SpringBoot Undertow: как отправить рабочую нить

Глядя на класс UndertowEmbeddedServletContainer.class, это выглядит как нет никакого способа, чтобы это поведение, так как только 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); 

} 

По умолчанию в отлива все запросы обрабатываются IO-Thread для неблокирующих операций. Означает ли это, что каждое выполнение @Controller будет обрабатываться неблокирующим потоком? или есть решение для выбора из IO-THREAD или WORKER-THREAD?

Я пытаюсь написать обходной путь, но этот код довольно uggly, и, возможно, кто-то имеет лучшее решение:

BlockingHandler.class

@Target({ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface BlockingHandler { 

    String contextPath() default "/"; 

} 

UndertowInitializer.class

public class UndertowInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { 

    @Override 
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) { 
     configurableApplicationContext.addBeanFactoryPostProcessor(new UndertowHandlerPostProcessor()); 
    } 

} 

UndertowHandlerPostProc essor.class

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 
    } 
} 

переопределение UndertowEmbeddedServletContainerFactory.class

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; 
    } 
} 

... 

переопределение UndertowEmbeddedServletContainer.class

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); 
} 

, наконец создать HttpHandler, отправляющих к рабочему потоку

@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"); 
    } 

}

Как вы можете видеть, мой "решение" на самом деле тяжелая, и я был бы очень признателен любой помогите его упростить.

Спасибо

ответ

6

Вам ничего не нужно.

В конфигурации по умолчанию Underwow от Spring Boot используется ServletInitialHandler Undertow перед весной MVC DispatcherServlet. Этот обработчик performs the exchange.isInIoThread() check and calls dispatch() if necessary.

Если вы разместите точку останова в своем @Controller, вы увидите, что она вызвана потоком с именем XNIO-1 task-n, который является рабочим потоком (потоки ввода-вывода называются XNIO-1 I/O-n).

Смежные вопросы