Как лучше зарегистрировать Servlet как bean в Spring Boot?
По вводным: в документации по 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. Методы контролера вообще не вызываются, т.к. В консоль не выводятся сообщения из этих методов.
В консоли такой вывод:
- По вводным: gET "/servletOne/", parameters={}, headers={masked} in DispatcherServlet 'servletOne'
- По вводным: mapped to HandlerExecutionChain with [ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]] and 3 interceptors
- Resource not found
- По вводным: [NewSpringBootApp] [nio-8080-exec-1] Resolved [org.springframework.web.servlet.resource.NoResourceFoundException: No static resource servletOne.]
- По вводным: no view rendering, null ModelAndView returned.
- По вводным: completed 404 NOT_FOUND, headers={masked}
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
В 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; } }
Если вы исключили 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.