Как лучше зарегистрировать Servlet как bean в Spring Boot?

Ссылка скопирована
1 ответ

По вводным: в документации по Spring Boot 3.5.3 сказано:
По вводным: any Servlet, Filter, or servlet *Listener instance that is a Spring bean is registered with the embedded container.

По вводным: пытаюсь зарегистрировать два Servlet во встроенном контейнере:

package com.springbootapp.main; @SpringBootApplication(exclude= {DispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class}) public class NewSpringBootAppApplication { public static void main(String[] args) { SpringApplication.run(NewSpringBootAppApplication.class, args); } @Bean public Servlet servletOne() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(ConfigOne.class); dispatcherServlet.setApplicationContext(applicationContext); return dispatcherServlet; } @Bean public Servlet servletTwo() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(ConfigTwo.class); dispatcherServlet.setApplicationContext(applicationContext); return dispatcherServlet; } }
package dispOne; @Configuration @ComponentScan @EnableWebMvc public class ConfigOne { }
package dispOne; @Controller @RequestMapping("/") public class ControllerOne { @GetMapping("/") String getIndex() { System.out.println("ControllerOne getIndex"); return "indexOne"; } }

По вводным: классы ConfigTwo и ControllerTwo лежат в пакете dispTwo и аналогичны, за исключением, что в ControllerTwo возвращается indexTwo.

По вводным: view лежат в resources/templates/.

Сейчас ситуация такая: по итогу выдает ошибку 404. Методы контролера вообще не вызываются, т.к. В консоль не выводятся сообщения из этих методов.

В консоли такой вывод:

  1. По вводным: gET "/servletOne/", parameters={}, headers={masked} in DispatcherServlet 'servletOne'
  2. По вводным: mapped to HandlerExecutionChain with [ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]] and 3 interceptors
  3. Resource not found
  4. По вводным: [NewSpringBootApp] [nio-8080-exec-1] Resolved [org.springframework.web.servlet.resource.NoResourceFoundException: No static resource servletOne.]
  5. По вводным: no view rendering, null ModelAndView returned.
  6. По вводным: completed 404 NOT_FOUND, headers={masked}
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Никита Орлов Ответ

В Spring Boot любой Servlet, объявленный как Spring bean, действительно может быть зарегистрирован во встроенном контейнере, но если у вас несколько servlet-ов, лучше не возвращать просто Servlet bean без явной привязки URL. Для нескольких сервлетов используйте ServletRegistrationBean: так вы явно задаете mapping, имя и порядок регистрации.

Пример:

@Configuration
public class ServletConfig {
 
    @Bean
    public ServletRegistrationBean<DispatcherServlet> servletOne() {
        AnnotationConfigWebApplicationContext context =
            new AnnotationConfigWebApplicationContext();
        context.register(FirstMvcConfig.class);
 
        DispatcherServlet servlet = new DispatcherServlet(context);
 
        ServletRegistrationBean<DispatcherServlet> bean =
            new ServletRegistrationBean<>(servlet, "/one/*");
        bean.setName("servletOne");
        bean.setLoadOnStartup(1);
        return bean;
    }
 
    @Bean
    public ServletRegistrationBean<DispatcherServlet> servletTwo() {
        AnnotationConfigWebApplicationContext context =
            new AnnotationConfigWebApplicationContext();
        context.register(SecondMvcConfig.class);
 
        DispatcherServlet servlet = new DispatcherServlet(context);
 
        ServletRegistrationBean<DispatcherServlet> bean =
            new ServletRegistrationBean<>(servlet, "/two/*");
        bean.setName("servletTwo");
        bean.setLoadOnStartup(2);
        return bean;
    }
}

@Configuration public class ServletConfig { @Bean public ServletRegistrationBean<DispatcherServlet> servletOne() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(FirstMvcConfig.class); DispatcherServlet servlet = new DispatcherServlet(context); ServletRegistrationBean<DispatcherServlet> bean = new ServletRegistrationBean<>(servlet, "/one/*"); bean.setName("servletOne"); bean.setLoadOnStartup(1); return bean; } @Bean public ServletRegistrationBean<DispatcherServlet> servletTwo() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(SecondMvcConfig.class); DispatcherServlet servlet = new DispatcherServlet(context); ServletRegistrationBean<DispatcherServlet> bean = new ServletRegistrationBean<>(servlet, "/two/*"); bean.setName("servletTwo"); bean.setLoadOnStartup(2); return bean; } }

Если вы исключили DispatcherServletAutoConfiguration и ErrorMvcAutoConfiguration, вы берете на себя больше ручной настройки. Это нормально для эксперимента, но для обычного приложения чаще проще оставить стандартный DispatcherServlet и добавлять контроллеры/роуты, а не создавать несколько DispatcherServlet.

Если servlet bean возвращается без ServletRegistrationBean, Boot может зарегистрировать его на default mapping или конфликтовать с уже существующим dispatcherServlet. Отсюда странное поведение: один servlet работает, другой нет, mapping не тот или приложение падает на старте.

Проверьте также, что у каждого DispatcherServlet свой WebApplicationContext и свой набор @Configuration. Если оба смотрят в один контекст, вы можете получить пересечение контроллеров и mapping-ов.

Вывод: для нескольких servlet-ов в Spring Boot регистрируйте не Servlet напрямую, а ServletRegistrationBean с явными URL. А если задача просто разделить API по путям, лучше использовать один стандартный DispatcherServlet и обычные @RequestMapping.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно