Spring Boot con mĂșltiples DispatcherServlet, cada uno con sus propios @Controllers
spring-mvc servlets (1)
¡Lo tengo funcionando de alguna manera!
Aquí está mi diseño del paquete:
test.foo.
FooConfig.java
FooController.java
test.bar.
BarConfig.java
BarController.java
test.app.
Application.java
MyService.java
src/main/resources/application.properties
Aplicación.java:
@SpringBootApplication(exclude=DispatcherServletAutoConfiguration.class)
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Bean
public ServletRegistrationBean foo() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(FooConfig.class);
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/foo/*");
servletRegistrationBean.setName("foo");
return servletRegistrationBean;
}
@Bean
public ServletRegistrationBean bar() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(BarConfig.class);
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/bar/*");
servletRegistrationBean.setName("bar");
return servletRegistrationBean;
}
}
- La
exclude
impide que Spring Boot cree su propioDispatcherServlet
con/
mapping. Puede eliminar esa línea, si desea que la asignación o definir su propia. - Puede agregar
servletRegistrationBean.setLoadOnStartup(1)
si desea que sus Servlets se inicialicen al iniciar la aplicación. De lo contrario, esperará la primera solicitud de ese servlet. - Es importante establecer
servletRegistrationBean.setName(...)
, de lo contrario, los servlets se anularán entre sí.
FooConfig.java & BarConfig.java:
@Configuration @ComponentScan @EnableWebMvc
public class FooConfig { }
-
@EnableWebMvc
habilitará la exploración de componentes. Sin él, no encontrará la clase@Controller
.
El código de Controlador y Servicio no es importante. Solo debes saber que si tienes @RequestMapping("/foo")
dentro de FooController
, la solicitud debe ser GET /foo/foo
porque la asignación de URL del Servlet es /foo/*
. No es posible llamar a la URL GET /foo
porque la asignación de la URL del Servlet necesita un /
al final de su ruta (en otras palabras: GET /foo
buscará un Servlet con /
mapping), aunque @RequestMapping("")
debe ser llamado a través de GET /foo/
. Y, por supuesto, no fue posible usar /foo
o /foo*
como asignación de Servlet (o simplemente no encontré la configuración correcta para eso)
Ámbito: los controladores no pueden verse entre sí, aunque no es posible que @Autowired
los haya @Autowired
. Además, el Servicio no puede @Autowired
ninguno de los Controladores. Pero los Controladores pueden @Autowired
el Servicio.
Aunque es una jerarquía de contexto padre-hijo clásica.
Lo único "malo" es que necesitamos @EnableMvcConfig
y no obtenemos el azúcar configurado automáticamente desde Spring boot dentro del contexto. El contexto padre se está configurando automáticamente. Puse algunas cosas de la base de datos dentro de application.properties
e hice una consulta dentro de MyService
que MyService
llamó y ¡funcionó a la perfección! :)
Espero que esto pueda ayudar a algunas personas!
Básicamente quiero dividir mi aplicación en 2 partes. Cada parte tiene su propio material de seguridad y el propio @Controller
s. Los @Services
deben ser accesibles desde ambas partes.
Así que pensé, debería obtener 2 DispatcherServlet
. Uno escucha /admin/*
y el segundo escucha todo lo demás ( /
). Cada uno de ellos tendrá su propio AnnotationConfigWebApplicationContext
para que pueda tener una exploración de componentes separada para los @Controller
s.
Y como Spring Boot proporciona un DispatcherServlet
escucha dentro /
fuera de la caja, pensé, solo puedo agregar una segunda:
@Configuration
public class MyConfig {
@Bean(name="myDS")
public DispatcherServlet myDS(ApplicationContext applicationContext) {
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.setParent(applicationContext);
webContext.register(MyConfig2.class);
// webContext.refresh();
return new DispatcherServlet(webContext);
}
@Bean
public ServletRegistrationBean mySRB(@Qualifier("myDS") DispatcherServlet dispatcherServlet) {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet);
servletRegistrationBean.addUrlMappings("/admin/*");
servletRegistrationBean.setName("adminServlet");
return servletRegistrationBean;
}
}
La clase MyConfig2
, solo tiene @Configuration
y @ComponentScan
. Dentro del mismo paquete hay un @Controller
.
Al iniciar la aplicación, puedo ver que se está registrando el segundo mapeo de servlet, pero no el @Controller
. Además, ahora puedo acceder a todos los @Controllers
desde /
y /admin
.
¿Alguna idea de cómo puedo hacer que esto funcione?